|
1 | 1 | import fs from 'fs'; |
2 | 2 | import type { Reporter, TestCase, TestModule, TestSuite, Vitest } from 'vitest/node'; |
3 | 3 |
|
4 | | -function* formatTestCase(testCase: TestCase, prefixes: string[]) { |
| 4 | +function* formatTestCase(testCase: TestCase) { |
5 | 5 | const passed = testCase.ok(); |
6 | 6 | const diagnostics = testCase.diagnostic(); |
7 | 7 | const durationStr = diagnostics ? `${diagnostics.duration.toFixed(0)}ms` : ''; |
8 | 8 |
|
9 | | - if (prefixes.length > 0) { |
10 | | - yield `- ${passed ? '✅' : '❌'} ${prefixes.join(' > ')} > ${testCase.name} ${durationStr}\n`; |
11 | | - } else { |
12 | | - yield `- ${passed ? '✅' : '❌'} ${testCase.name} ${durationStr}\n`; |
13 | | - } |
| 9 | + yield `${passed ? '✅' : '❌'} ${testCase.name} ${durationStr}\n`; |
14 | 10 | } |
15 | 11 |
|
16 | | -function* formatTestSuite(suite: TestSuite, prefixes: string[]): Generator<string> { |
| 12 | +function* formatTestSuite(suite: TestSuite): Generator<string> { |
17 | 13 | const suiteName = suite.name; |
| 14 | + const passed = suite.ok(); |
| 15 | + |
| 16 | + yield `${passed ? '✅' : '❌'} ${suiteName}<ul>`; |
18 | 17 |
|
19 | 18 | for (const child of suite.children) { |
20 | 19 | if (child.type === 'suite') { |
21 | | - yield* formatTestSuite(child, [...prefixes, suiteName]); |
| 20 | + yield* formatTestSuite(child); |
22 | 21 | } else { |
23 | | - yield* formatTestCase(child, [...prefixes, suiteName]); |
| 22 | + yield '<li>'; |
| 23 | + yield* formatTestCase(child); |
| 24 | + yield '</li>'; |
24 | 25 | } |
25 | 26 | } |
| 27 | + |
| 28 | + yield '</ul>\n'; |
26 | 29 | } |
27 | 30 |
|
28 | 31 | function getTestCount(item: TestModule | TestSuite | TestCase): number { |
@@ -51,28 +54,38 @@ export default class GithubActionsSummaryReporter implements Reporter { |
51 | 54 | onTestRunEnd(modules: readonly TestModule[]) { |
52 | 55 | if (!this.writeStream) return; |
53 | 56 |
|
54 | | - this.writeStream.write('### Test Results'); |
| 57 | + this.writeStream.write('## Test Results\n'); |
55 | 58 | for (const testModule of modules) { |
56 | 59 | const passed = testModule.ok(); |
57 | 60 | const testCount = getTestCount(testModule); |
58 | 61 |
|
59 | 62 | this.writeStream.write(`${passed ? '✅' : '❌'} (fileName) (${testCount} test${testCount === 1 ? '' : 's'}) \n`); |
60 | 63 |
|
| 64 | + this.writeStream.write('<ul>'); |
61 | 65 | for (const child of testModule.children) { |
62 | | - const formatter = child.type === 'suite' ? formatTestSuite(child, []) : formatTestCase(child, []); |
| 66 | + const formatter = child.type === 'suite' ? formatTestSuite(child) : formatTestCase(child); |
63 | 67 | const line = Array.from(formatter).join(''); |
64 | | - this.writeStream.write(line); |
| 68 | + this.writeStream.write(`<li>${line}</li>`); |
65 | 69 | } |
| 70 | + this.writeStream.write('</ul>'); |
66 | 71 |
|
67 | 72 | const diagnostics = testModule.diagnostic(); |
68 | 73 | const totalDuration = diagnostics.duration.toFixed(0); |
69 | 74 |
|
70 | 75 | this.writeStream.write('\n\n'); |
71 | 76 | this.writeStream.write('#### Summary\n'); |
72 | | - this.writeStream.write('Test Files\n'); |
73 | | - this.writeStream.write(` Tests ${testCount}\n`); |
74 | | - this.writeStream.write(' Start at\n'); |
75 | | - this.writeStream.write(` Duration: ${totalDuration}ms\n`); |
| 77 | + this.writeStream.write('<table>'); |
| 78 | + |
| 79 | + function formatRow(...items: string[]) { |
| 80 | + const tds = items.map(item => `<td>${item}</td>`); |
| 81 | + return `<tr>${tds.join('')}</tr>\n`; |
| 82 | + } |
| 83 | + |
| 84 | + this.writeStream.write(formatRow('Test Files', '')); |
| 85 | + this.writeStream.write(formatRow('Tests', testCount.toString())); |
| 86 | + this.writeStream.write(formatRow('Start at', '')); |
| 87 | + this.writeStream.write(formatRow('Duration', `${totalDuration}ms`)); |
| 88 | + this.writeStream.write('</table>'); |
76 | 89 | } |
77 | 90 |
|
78 | 91 | this.writeStream.close(); |
|
0 commit comments