phase-7: code restructure
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// 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`;
|
||||
}
|
||||
Reference in New Issue
Block a user