| 4 | import type { Counts, TestResult, TestResults } from './results.ts' |
| 5 | |
| 6 | export class SpecReporter implements Reporter { |
| 7 | #failures: { suiteName: string; name: string; error: TestResult['error'] }[] = [] |
| 8 | #files = new Set<string>() |
| 9 | #suites = new Set<string>() |
| 10 | |
| 11 | onSectionStart(label: string) { |
| 12 | console.log(label) |
| 13 | } |
| 14 | |
| 15 | onResult(results: TestResults, env?: string) { |
| 16 | for (let test of results.tests) { |
| 17 | if (test.filePath) this.#files.add(test.filePath) |
| 18 | if (test.suiteName) this.#suites.add(test.suiteName) |
| 19 | } |
| 20 | |
| 21 | let suiteMap = new Map<string, TestResult[]>() |
| 22 | for (let test of results.tests) { |
| 23 | let suite = test.suiteName || 'Global' |
| 24 | if (!suiteMap.has(suite)) suiteMap.set(suite, []) |
| 25 | suiteMap.get(suite)!.push(test) |
| 26 | } |
| 27 | |
| 28 | let envLabel = env ? ` ${colors.dim(`[${env}]`)}` : '' |
| 29 | let lastParts: string[] = [] |
| 30 | |
| 31 | // Pre-compute aggregate test results for each path prefix so non-leaf |
| 32 | // suite headings can be colored the same way as leaf headings. |
| 33 | let prefixTests = new Map<string, TestResult[]>() |
| 34 | for (let [suiteName, tests] of suiteMap) { |
| 35 | let parts = suiteName.split(' > ') |
| 36 | for (let i = 0; i < parts.length; i++) { |
| 37 | let prefix = parts.slice(0, i + 1).join(' > ') |
| 38 | if (!prefixTests.has(prefix)) prefixTests.set(prefix, []) |
| 39 | prefixTests.get(prefix)!.push(...tests) |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | for (let [suiteName, suiteTests] of suiteMap) { |
| 44 | let parts = suiteName.split(' > ') |
| 45 | |
| 46 | // Find where this path diverges from the last rendered path |
| 47 | let commonLen = 0 |
| 48 | while ( |
| 49 | commonLen < lastParts.length && |
| 50 | commonLen < parts.length && |
| 51 | lastParts[commonLen] === parts[commonLen] |
| 52 | ) { |
| 53 | commonLen++ |
| 54 | } |
| 55 | |
| 56 | // Print each new path component |
| 57 | for (let i = commonLen; i < parts.length; i++) { |
| 58 | let indent = ' '.repeat(i) |
| 59 | let isLeaf = i === parts.length - 1 |
| 60 | |
| 61 | if (isLeaf) { |
| 62 | let totalDuration = suiteTests.reduce((sum, t) => sum + t.duration, 0) |
| 63 | let suiteHasFailed = suiteTests.some((t) => t.status === 'failed') |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…