155 lines
4.7 KiB
TypeScript
155 lines
4.7 KiB
TypeScript
import { describe, expect, it } from 'bun:test';
|
|
import type { Task } from '@/lib/types';
|
|
import { buildTaskNotification } from '@/lib/server/task-notifications';
|
|
|
|
function baseTask(overrides: Partial<Omit<Task, 'notification'>> = {}): Omit<Task, 'notification'> {
|
|
return {
|
|
id: 'task-1',
|
|
user_id: 'user-1',
|
|
task_type: 'sync_filings',
|
|
status: 'running',
|
|
stage: 'sync.extract_taxonomy',
|
|
stage_detail: 'Extracting XBRL taxonomy for 0000320193-26-000001',
|
|
stage_context: {
|
|
progress: {
|
|
current: 2,
|
|
total: 5,
|
|
unit: 'filings'
|
|
},
|
|
counters: {
|
|
hydrated: 1,
|
|
failed: 0
|
|
},
|
|
subject: {
|
|
ticker: 'AAPL',
|
|
accessionNumber: '0000320193-26-000001'
|
|
}
|
|
},
|
|
resource_key: 'sync_filings:AAPL',
|
|
notification_read_at: null,
|
|
notification_silenced_at: null,
|
|
priority: 50,
|
|
payload: {
|
|
ticker: 'AAPL',
|
|
limit: 20
|
|
},
|
|
result: null,
|
|
error: null,
|
|
attempts: 1,
|
|
max_attempts: 3,
|
|
workflow_run_id: 'run-1',
|
|
created_at: '2026-03-09T10:00:00.000Z',
|
|
updated_at: '2026-03-09T10:05:00.000Z',
|
|
finished_at: null,
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
describe('task notification builder', () => {
|
|
it('builds progress-driven notifications for running sync jobs', () => {
|
|
const notification = buildTaskNotification(baseTask());
|
|
|
|
expect(notification.title).toBe('Filing sync');
|
|
expect(notification.statusLine).toContain('Running');
|
|
expect(notification.progress?.percent).toBe(40);
|
|
expect(notification.stats.some((stat) => stat.label === 'Hydrated' && stat.value === '1')).toBe(true);
|
|
expect(notification.actions[0]).toMatchObject({
|
|
id: 'open_filings',
|
|
primary: true,
|
|
href: '/filings?ticker=AAPL'
|
|
});
|
|
});
|
|
|
|
it('builds report actions for completed analyze jobs', () => {
|
|
const notification = buildTaskNotification(baseTask({
|
|
task_type: 'analyze_filing',
|
|
status: 'completed',
|
|
stage: 'completed',
|
|
stage_detail: 'Analysis report generated for AAPL 10-Q 0000320193-26-000001.',
|
|
stage_context: {
|
|
subject: {
|
|
ticker: 'AAPL',
|
|
accessionNumber: '0000320193-26-000001',
|
|
label: '10-Q'
|
|
}
|
|
},
|
|
payload: {
|
|
accessionNumber: '0000320193-26-000001'
|
|
},
|
|
result: {
|
|
ticker: 'AAPL',
|
|
accessionNumber: '0000320193-26-000001',
|
|
filingType: '10-Q',
|
|
model: 'test-model'
|
|
},
|
|
finished_at: '2026-03-09T10:06:00.000Z'
|
|
}));
|
|
|
|
expect(notification.tone).toBe('success');
|
|
expect(notification.actions[0]).toMatchObject({
|
|
id: 'open_analysis_report',
|
|
label: 'Open summary',
|
|
primary: true
|
|
});
|
|
expect(notification.actions[0]?.href).toContain('/analysis/reports/AAPL/0000320193-26-000001');
|
|
expect(notification.stats.some((stat) => stat.label === 'Form' && stat.value === '10-Q')).toBe(true);
|
|
});
|
|
|
|
it('keeps filings navigation available for failed analyze jobs', () => {
|
|
const notification = buildTaskNotification(baseTask({
|
|
task_type: 'analyze_filing',
|
|
status: 'failed',
|
|
stage: 'analyze.fetch_document',
|
|
stage_detail: 'Could not load the primary filing document.',
|
|
error: 'Could not load the primary filing document for AAPL · 0000320193-26-000001. Retry the job after confirming the SEC source is reachable.',
|
|
stage_context: {
|
|
subject: {
|
|
ticker: 'AAPL',
|
|
accessionNumber: '0000320193-26-000001'
|
|
}
|
|
},
|
|
payload: {
|
|
accessionNumber: '0000320193-26-000001'
|
|
},
|
|
result: null,
|
|
finished_at: '2026-03-09T10:06:00.000Z'
|
|
}));
|
|
|
|
expect(notification.tone).toBe('error');
|
|
expect(notification.statusLine).toBe('Failed during fetch primary document');
|
|
expect(notification.detailLine).toBe('Could not load the primary filing document.');
|
|
expect(notification.actions.some((action) => action.id === 'open_filings')).toBe(true);
|
|
});
|
|
|
|
it('adds research navigation for completed research brief jobs', () => {
|
|
const notification = buildTaskNotification(baseTask({
|
|
task_type: 'research_brief',
|
|
status: 'completed',
|
|
stage: 'completed',
|
|
stage_detail: 'Generated research brief artifact for NVDA.',
|
|
stage_context: {
|
|
subject: {
|
|
ticker: 'NVDA'
|
|
}
|
|
},
|
|
payload: {
|
|
ticker: 'NVDA',
|
|
query: 'Update the thesis'
|
|
},
|
|
result: {
|
|
ticker: 'NVDA',
|
|
artifactId: 12,
|
|
model: 'test-model'
|
|
},
|
|
finished_at: '2026-03-09T10:06:00.000Z'
|
|
}));
|
|
|
|
expect(notification.actions[0]).toMatchObject({
|
|
id: 'open_research',
|
|
href: '/research?ticker=NVDA',
|
|
primary: true
|
|
});
|
|
expect(notification.stats.some((stat) => stat.label === 'Artifact' && stat.value === '12')).toBe(true);
|
|
});
|
|
});
|