Files
market_screener/scripts/summary-reporter.ts
T
2026-06-06 22:55:43 -04:00

49 lines
1.6 KiB
TypeScript

// Minimal test reporter: silent on pass, prints failures in full, ends with one summary line.
import type { TestEvent } from 'node:test/reporters';
interface Failure {
name: string;
reason: string;
}
export default async function* summaryReporter(
source: AsyncIterable<TestEvent>,
): AsyncGenerator<string> {
const failures: Failure[] = [];
let passed = 0,
failed = 0,
totalMs = 0;
for await (const event of source) {
// Skip file-level wrapper events (name ends in .ts) — only count individual tests.
if ((event.data as { name?: string })?.name?.endsWith('.ts')) continue;
if (event.type === 'test:pass') {
passed++;
totalMs += (event.data as { details?: { duration_ms?: number } }).details?.duration_ms ?? 0;
} else if (event.type === 'test:fail') {
failed++;
totalMs += (event.data as { details?: { duration_ms?: number } }).details?.duration_ms ?? 0;
const err = (
event.data as { details?: { error?: { cause?: { message?: string }; message?: string } } }
).details?.error;
failures.push({
name: (event.data as { name?: string }).name ?? 'unknown',
reason: err?.cause?.message ?? err?.message ?? 'unknown',
});
}
}
if (failures.length) {
yield '\nFailed tests:\n';
for (const f of failures) yield `${f.name}\n ${f.reason}\n`;
yield '\n';
}
const status = failed === 0 ? '✅' : '❌';
const time = (totalMs / 1000).toFixed(2);
yield `${status} ${passed + failed} tests: ${passed} passed`;
if (failed) yield `, ${failed} failed`;
yield ` (${time}s)\n`;
}