import test from 'node:test'; import assert from 'node:assert/strict'; import { EdgarPoller } from '../server/domains/news/pollers/EdgarPoller.js'; import { PrWirePoller } from '../server/domains/news/pollers/PrWirePoller.js'; import { RssParser } from '../server/domains/news/rss.js'; import { noopLogger } from '../server/domains/shared/utils/logger.js'; const EDGAR_ATOM = ` Latest Filings 8-K - APPLE INC (0000320193) (Filer) 2026-06-09T13:01:02-04:00 urn:tag:sec.gov,2008:accession-number=0000320193-26-000001 8-K - UNKNOWN CO (0009999999) (Filer) 2026-06-09T13:05:00-04:00 urn:tag:sec.gov,2008:accession-number=x `; const PRWIRE_RSS = ` Acme Corp (NYSE: ACME) Announces Record Q2 Results https://www.example.com/acme-q2 Tue, 09 Jun 2026 12:00:00 GMT Local bakery wins award https://www.example.com/bakery Tue, 09 Jun 2026 11:00:00 GMT No public companies here. `; test('news pollers', async (t) => { await t.test('EdgarPoller maps CIK to ticker and filters by universe', () => { const poller = new EdgarPoller(noopLogger, 'test-agent'); poller.setTickerMap(new Map([['0000320193', 'AAPL']])); const stories = poller.parseFeed(EDGAR_ATOM, '8-K', 'regulatory', new Set(['AAPL'])); assert.equal(stories.length, 1); // unknown CIK dropped assert.deepEqual(stories[0].tickers, ['AAPL']); assert.equal(stories[0].source, 'edgar'); assert.equal(stories[0].catalystHint, 'regulatory'); assert.ok(stories[0].headline.startsWith('8-K filing:')); assert.ok(stories[0].headline.includes('APPLE INC')); assert.ok(stories[0].url.includes('sec.gov')); }); await t.test('EdgarPoller drops universe misses', () => { const poller = new EdgarPoller(noopLogger, 'test-agent'); poller.setTickerMap(new Map([['0000320193', 'AAPL']])); const stories = poller.parseFeed(EDGAR_ATOM, '8-K', 'regulatory', new Set(['MSFT'])); assert.equal(stories.length, 0); }); await t.test('PrWirePoller extracts exchange-tagged tickers', () => { const stories = PrWirePoller.parseFeed(PRWIRE_RSS); assert.equal(stories.length, 1); // bakery story has no tickers → skipped assert.deepEqual(stories[0].tickers.sort(), ['ACME', 'BETA']); assert.equal(stories[0].source, 'prwire'); assert.ok(stories[0].publishedAt.startsWith('2026-06-09')); }); await t.test('extractTickers handles exchange tag variants', () => { assert.deepEqual(PrWirePoller.extractTickers('(NYSE: ABC)'), ['ABC']); assert.deepEqual(PrWirePoller.extractTickers('(Nasdaq: xyz)'), ['XYZ']); assert.deepEqual(PrWirePoller.extractTickers('(NYSE American: BRK.B)'), ['BRK.B']); assert.deepEqual(PrWirePoller.extractTickers('(OTCQB: TINY)'), ['TINY']); assert.deepEqual(PrWirePoller.extractTickers('no tags here'), []); }); await t.test('RssParser decodes entities and strips CDATA', () => { const block = 'A & B say "hi"'; assert.equal(RssParser.tag(block, 'title'), 'A & B say "hi"'); const cdata = 'bold here]]>'; assert.equal(RssParser.tag(cdata, 'description'), 'Text bold here'); }); });