49 lines
1.6 KiB
TypeScript
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`;
|
|
}
|