Prioritize SEC financials for 10-K/10-Q and keep other filings qualitative
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it, mock } from 'bun:test';
|
||||
import {
|
||||
fetchFilingMetricsForFilings,
|
||||
fetchPrimaryFilingText,
|
||||
normalizeSecDocumentText,
|
||||
resolvePrimaryFilingUrl,
|
||||
@@ -81,4 +82,111 @@ describe('sec filing text helpers', () => {
|
||||
expect(result?.truncated).toBe(true);
|
||||
expect(result?.text.length).toBeLessThanOrEqual(1_000);
|
||||
});
|
||||
|
||||
it('maps SEC companyfacts metrics to each filing by accession', async () => {
|
||||
const fetchMock = mock(async (_input: RequestInfo | URL, _init?: RequestInit) => {
|
||||
return new Response(JSON.stringify({
|
||||
facts: {
|
||||
'us-gaap': {
|
||||
Revenues: {
|
||||
units: {
|
||||
USD: [
|
||||
{ accn: '0000320193-25-000010', val: 101_000, filed: '2025-11-01', form: '10-Q' },
|
||||
{ accn: '0000320193-25-000020', val: 111_000, filed: '2026-02-01', form: '10-Q' }
|
||||
]
|
||||
}
|
||||
},
|
||||
NetIncomeLoss: {
|
||||
units: {
|
||||
USD: [
|
||||
{ accn: '0000320193-25-000010', val: 21_000, filed: '2025-11-01', form: '10-Q' },
|
||||
{ accn: '0000320193-25-000020', val: 25_000, filed: '2026-02-01', form: '10-Q' }
|
||||
]
|
||||
}
|
||||
},
|
||||
Assets: {
|
||||
units: {
|
||||
USD: [
|
||||
{ accn: '0000320193-25-000010', val: 405_000, filed: '2025-11-01', form: '10-Q' },
|
||||
{ accn: '0000320193-25-000020', val: 410_000, filed: '2026-02-01', form: '10-Q' }
|
||||
]
|
||||
}
|
||||
},
|
||||
CashAndCashEquivalentsAtCarryingValue: {
|
||||
units: {
|
||||
USD: [
|
||||
{ accn: '0000320193-25-000010', val: 65_000, filed: '2025-11-01', form: '10-Q' },
|
||||
{ accn: '0000320193-25-000020', val: 70_000, filed: '2026-02-01', form: '10-Q' }
|
||||
]
|
||||
}
|
||||
},
|
||||
LongTermDebt: {
|
||||
units: {
|
||||
USD: [
|
||||
{ accn: '0000320193-25-000010', val: 95_000, filed: '2025-11-01', form: '10-Q' },
|
||||
{ accn: '0000320193-25-000020', val: 98_000, filed: '2026-02-01', form: '10-Q' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}), { status: 200 });
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = fetchMock;
|
||||
|
||||
try {
|
||||
const map = await fetchFilingMetricsForFilings('0000320193', 'AAPL', [
|
||||
{
|
||||
accessionNumber: '0000320193-25-000010',
|
||||
filingDate: '2025-11-01',
|
||||
filingType: '10-Q'
|
||||
},
|
||||
{
|
||||
accessionNumber: '0000320193-25-000020',
|
||||
filingDate: '2026-02-01',
|
||||
filingType: '10-Q'
|
||||
}
|
||||
]);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(map.get('0000320193-25-000010')?.revenue).toBe(101_000);
|
||||
expect(map.get('0000320193-25-000010')?.netIncome).toBe(21_000);
|
||||
expect(map.get('0000320193-25-000020')?.revenue).toBe(111_000);
|
||||
expect(map.get('0000320193-25-000020')?.cash).toBe(70_000);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it('returns null-valued metrics when companyfacts lookup fails', async () => {
|
||||
const fetchMock = mock(async (_input: RequestInfo | URL, _init?: RequestInit) => {
|
||||
return new Response('error', { status: 500 });
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = fetchMock;
|
||||
|
||||
try {
|
||||
const map = await fetchFilingMetricsForFilings('0000320193', 'AAPL', [
|
||||
{
|
||||
accessionNumber: '0000320193-25-000010',
|
||||
filingDate: '2025-11-01',
|
||||
filingType: '10-Q'
|
||||
}
|
||||
]);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(map.get('0000320193-25-000010')).toEqual({
|
||||
revenue: null,
|
||||
netIncome: null,
|
||||
totalAssets: null,
|
||||
cash: null,
|
||||
debt: null
|
||||
});
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user