88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { SignalSnapshotRepository } from '../server/domains/shared/persistence/SignalSnapshotRepository.js';
|
|
import { MockDatabaseConnection } from './helpers/mockDb.js';
|
|
import type { DatabaseConnection } from '../server/domains/shared/db/index.js';
|
|
import type { ScoreResult } from '../server/domains/shared/types/index.js';
|
|
|
|
const passResult: ScoreResult = {
|
|
label: '🟢 BUY (High Conviction)',
|
|
tier: 'PASS',
|
|
score: 9,
|
|
scoreSummary: 'Score: 9',
|
|
audit: { passedGates: true, breakdown: { roe: 3 }, coverage: { active: 6, total: 11 } },
|
|
};
|
|
|
|
const rejectResult: ScoreResult = {
|
|
label: '🔴 REJECT',
|
|
tier: 'REJECT',
|
|
score: null,
|
|
scoreSummary: 'Gate failed: P/E 40 > 15',
|
|
audit: { passedGates: false, failures: ['P/E 40 > 15'] },
|
|
};
|
|
|
|
function repo(): SignalSnapshotRepository {
|
|
return new SignalSnapshotRepository(
|
|
new MockDatabaseConnection() as unknown as DatabaseConnection,
|
|
);
|
|
}
|
|
|
|
test('SignalSnapshotRepository', async (t) => {
|
|
await t.test('record() builds a valid UPSERT (16 params, no throw)', () => {
|
|
// QueryBuilder validates placeholder count — a param mismatch throws here.
|
|
assert.doesNotThrow(() =>
|
|
repo().record({
|
|
ticker: 'aapl',
|
|
assetType: 'STOCK',
|
|
price: 189.5,
|
|
signal: '✅ Strong Buy',
|
|
fundamental: passResult,
|
|
inflated: passResult,
|
|
rateRegime: 'NORMAL',
|
|
}),
|
|
);
|
|
});
|
|
|
|
await t.test('record() tolerates gate-failed results (null score)', () => {
|
|
assert.doesNotThrow(() =>
|
|
repo().record({
|
|
ticker: 'XYZ',
|
|
assetType: 'STOCK',
|
|
price: null,
|
|
signal: '❌ Avoid',
|
|
fundamental: rejectResult,
|
|
inflated: rejectResult,
|
|
}),
|
|
);
|
|
});
|
|
|
|
await t.test('recordBatch() returns count written', () => {
|
|
const n = repo().recordBatch([
|
|
{
|
|
ticker: 'AAPL',
|
|
assetType: 'STOCK',
|
|
price: 189.5,
|
|
signal: '✅ Strong Buy',
|
|
fundamental: passResult,
|
|
inflated: passResult,
|
|
},
|
|
{
|
|
ticker: 'MSFT',
|
|
assetType: 'STOCK',
|
|
price: 425.3,
|
|
signal: '🔄 Neutral',
|
|
fundamental: passResult,
|
|
inflated: passResult,
|
|
},
|
|
]);
|
|
assert.equal(n, 2);
|
|
});
|
|
|
|
await t.test('read methods build valid queries', () => {
|
|
const r = repo();
|
|
assert.deepEqual(r.history('aapl'), []);
|
|
assert.deepEqual(r.byDate('2026-06-09'), []);
|
|
assert.deepEqual(r.latestBefore('2026-06-09'), []);
|
|
});
|
|
});
|