fix bruno collection
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { ScreenerController } from '../server/domains/screener/screener.controller.js';
|
||||
import { ScreenerEngine } from '../server/domains/screener/ScreenerEngine.js';
|
||||
|
||||
import type {
|
||||
LiveAssetResult,
|
||||
MarketContext,
|
||||
Stock,
|
||||
} from '../server/domains/shared/types/index.js';
|
||||
import { ASSET_TYPE, SIGNAL } from '../server/domains/shared/config/constants.js';
|
||||
|
||||
// Mock implementations
|
||||
class MockScreenerEngine extends ScreenerEngine {
|
||||
async screenTickers(tickers: string[]) {
|
||||
const mockContext: MarketContext = {
|
||||
sp500Price: 5500,
|
||||
riskFreeRate: 4.5,
|
||||
vixLevel: 12.5,
|
||||
rateRegime: 'NORMAL',
|
||||
volatilityRegime: 'LOW',
|
||||
benchmarks: {
|
||||
marketPE: 20,
|
||||
techPE: 28,
|
||||
reitYield: 3.5,
|
||||
igSpread: 1.2,
|
||||
},
|
||||
};
|
||||
|
||||
// Return mock results for tested tickers
|
||||
const mockStock = {
|
||||
ticker: 'AAPL',
|
||||
type: ASSET_TYPE.STOCK,
|
||||
currentPrice: 189.5,
|
||||
metrics: {
|
||||
peRatio: 28.5,
|
||||
returnOnEquity: 95.2,
|
||||
freeCashFlow: 100000000,
|
||||
debtToEquity: 0.75,
|
||||
},
|
||||
getDisplayMetrics: () => ({
|
||||
peRatio: 28.5,
|
||||
returnOnEquity: 95.2,
|
||||
freeCashFlow: 100000000,
|
||||
}),
|
||||
} as unknown as Stock;
|
||||
|
||||
const mockResult: LiveAssetResult = {
|
||||
asset: mockStock,
|
||||
fundamentalScore: { label: '✓ BUY', scoreSummary: 'Quality gate PASS' },
|
||||
inflatedScore: { label: '✓ BUY', scoreSummary: 'Market adjusted gate PASS' },
|
||||
signal: SIGNAL.STRONG_BUY,
|
||||
};
|
||||
|
||||
return {
|
||||
STOCK: tickers.length > 0 ? [mockResult] : [],
|
||||
ETF: [],
|
||||
BOND: [],
|
||||
ERROR: [],
|
||||
marketContext: mockContext,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MockCatalystCache {
|
||||
async get() {
|
||||
return {
|
||||
tickers: ['AAPL', 'MSFT', 'NVDA'],
|
||||
stories: [
|
||||
{
|
||||
headline: 'Apple beats Q2 earnings',
|
||||
summary: 'Strong iPhone sales boost revenue',
|
||||
sentiment: 'positive',
|
||||
relatedTickers: ['AAPL'],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test('ScreenerController', async (t) => {
|
||||
await t.test('screen() processes valid ticker list', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const controller = new ScreenerController(engine, cache);
|
||||
|
||||
// Create a mock FastifyInstance with only the methods we need
|
||||
const mockApp = {
|
||||
post: () => {},
|
||||
get: () => {},
|
||||
};
|
||||
|
||||
// Register should succeed
|
||||
controller.register(mockApp as any);
|
||||
assert.ok(true);
|
||||
});
|
||||
|
||||
await t.test('screen() serializes assets correctly', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const _controller = new ScreenerController(engine, cache);
|
||||
|
||||
// Test private serialization method indirectly through results
|
||||
const results = await engine.screenTickers(['AAPL']);
|
||||
assert.equal(results.STOCK.length, 1);
|
||||
assert.ok(results.STOCK[0].asset.ticker === 'AAPL');
|
||||
});
|
||||
|
||||
await t.test('screen() handles empty ticker list', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const _controller = new ScreenerController(engine, cache);
|
||||
|
||||
const results = await engine.screenTickers([]);
|
||||
assert.equal(results.STOCK.length, 0);
|
||||
assert.equal(results.ETF.length, 0);
|
||||
assert.equal(results.BOND.length, 0);
|
||||
});
|
||||
|
||||
await t.test('catalysts() returns cached results', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const _controller = new ScreenerController(engine, cache);
|
||||
|
||||
const catalysts = await cache.get();
|
||||
assert.ok(Array.isArray(catalysts.tickers));
|
||||
assert.ok(Array.isArray(catalysts.stories));
|
||||
assert.equal(catalysts.tickers.length, 3);
|
||||
});
|
||||
|
||||
await t.test('catalysts() includes headlines and sentiment', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const _controller = new ScreenerController(engine, cache);
|
||||
|
||||
const catalysts = await cache.get();
|
||||
const story = catalysts.stories[0];
|
||||
assert.ok(story.headline);
|
||||
assert.ok(story.sentiment);
|
||||
assert.ok(story.relatedTickers);
|
||||
});
|
||||
|
||||
await t.test('controller registers POST /api/screen endpoint', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const controller = new ScreenerController(engine, cache);
|
||||
|
||||
let screenEndpointRegistered = false;
|
||||
const mockApp = {
|
||||
post: (path: string) => {
|
||||
if (path === '/api/screen') screenEndpointRegistered = true;
|
||||
},
|
||||
get: () => {},
|
||||
};
|
||||
|
||||
controller.register(mockApp as any);
|
||||
assert.ok(screenEndpointRegistered);
|
||||
});
|
||||
|
||||
await t.test('controller registers GET /api/screen/catalysts endpoint', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const cache = new MockCatalystCache() as any;
|
||||
const controller = new ScreenerController(engine, cache);
|
||||
|
||||
let catalystEndpointRegistered = false;
|
||||
const mockApp = {
|
||||
post: () => {},
|
||||
get: (path: string) => {
|
||||
if (path === '/api/screen/catalysts') catalystEndpointRegistered = true;
|
||||
},
|
||||
};
|
||||
|
||||
controller.register(mockApp as any);
|
||||
assert.ok(catalystEndpointRegistered);
|
||||
});
|
||||
|
||||
await t.test('screen() includes market context in response', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const results = await engine.screenTickers(['AAPL']);
|
||||
|
||||
assert.ok(results.marketContext);
|
||||
assert.ok(results.marketContext.sp500Price);
|
||||
assert.ok(results.marketContext.benchmarks);
|
||||
});
|
||||
|
||||
await t.test('screen() includes verdict signal in results', async () => {
|
||||
const engine = new MockScreenerEngine(null as any, null as any);
|
||||
const results = await engine.screenTickers(['AAPL']);
|
||||
|
||||
assert.equal(results.STOCK.length, 1);
|
||||
const result = results.STOCK[0];
|
||||
assert.ok(result.signal);
|
||||
assert.ok(result.fundamentalScore);
|
||||
assert.ok(result.inflatedScore);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user