Skip to content

Commit 7fce125

Browse files
committed
Add skipped and todo test handling
1 parent 67116aa commit 7fce125

File tree

6 files changed

+304
-150
lines changed

6 files changed

+304
-150
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"@typescript-eslint/no-shadow": "error",
1818
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
1919
"@typescript-eslint/no-require-imports": "error",
20-
"@typescript-eslint/array-type": "error",
20+
"@typescript-eslint/array-type": ["error", {"default": "generic"}],
2121
"@typescript-eslint/await-thenable": "error",
2222
"@typescript-eslint/ban-ts-comment": "error",
2323
"camelcase": "off",

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,19 @@
3737
"dependencies": {
3838
"@actions/core": "^1.10.0",
3939
"chalk": "^4.0.0",
40-
"jest": "^29.3.1"
40+
"jest": "^29.3.1",
41+
"jest-util": "^29.7.0"
4142
},
4243
"devDependencies": {
4344
"@babel/preset-env": "^7.19.4",
44-
"typescript": "^5.0.4",
4545
"@types/node": "^20.1.3",
4646
"@typescript-eslint/parser": "^5.59.5",
4747
"eslint": "^8.40.0",
4848
"eslint-plugin-github": "^4.7.0",
4949
"eslint-plugin-jest": "^27.2.1",
5050
"js-yaml": "^4.1.0",
5151
"prettier": "^3.0.0",
52-
"ts-jest": "^29.1.0"
52+
"ts-jest": "^29.1.0",
53+
"typescript": "^5.0.4"
5354
}
5455
}

src/gha.reporter.ts

Lines changed: 97 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,42 @@ import * as reporters from '@jest/reporters';
33
import {
44
AggregatedResult,
55
AssertionResult,
6+
Status,
67
Test,
78
TestContext,
89
TestResult
910
} from '@jest/test-result';
1011
import chalk from 'chalk';
12+
import {specialChars} from 'jest-util';
1113

12-
type ResultTree = {
14+
const ICONS = specialChars.ICONS;
15+
16+
type PerformanceInfo = {
17+
end: number;
18+
runtime: number;
19+
slow: boolean;
20+
start: number;
21+
};
22+
23+
type ResultTreeLeaf = {
1324
name: string;
14-
passed: boolean;
15-
performanceInfo: PerformanceInfo;
16-
children: (ResultTreeNode | ResultTreeLeaf)[];
25+
status: Status;
26+
duration: number;
27+
children: Array<never>;
1728
};
1829

1930
type ResultTreeNode = {
2031
name: string;
2132
passed: boolean;
22-
children: (ResultTreeNode | ResultTreeLeaf)[];
33+
children: Array<ResultTreeNode | ResultTreeLeaf>;
2334
};
2435

25-
type ResultTreeLeaf = {
36+
type ResultTree = {
37+
children: Array<ResultTreeLeaf | ResultTreeNode>;
2638
name: string;
2739
passed: boolean;
28-
duration: number;
29-
children: never[];
30-
};
31-
32-
type PerformanceInfo = {
33-
end: number;
34-
runtime: number;
35-
slow: boolean;
36-
start: number;
40+
performanceInfo: PerformanceInfo;
3741
};
38-
3942
export default class GithubActionsReporter extends reporters.BaseReporter {
4043
override onTestResult(
4144
test: Test,
@@ -44,10 +47,7 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
4447
): void {
4548
this.printFullResult(test.context, testResult);
4649
if (this.isLastTestSuite(results)) {
47-
core.info('');
48-
if (this.printFailedTestLogs(test, results)) {
49-
core.info('');
50-
}
50+
this.printFailedTestLogs(test, results);
5151
}
5252
}
5353

@@ -71,9 +71,9 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
7171
testContexts: Set<TestContext>,
7272
results: AggregatedResult
7373
): void {
74-
core.info('');
75-
core.info(reporters.utils.getSummary(results));
76-
core.info('Ran all test suites.');
74+
this.log('');
75+
this.log(reporters.utils.getSummary(results));
76+
this.log('Ran all test suites.');
7777
}
7878

7979
private printFullResult(context: TestContext, results: TestResult): void {
@@ -89,12 +89,11 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
8989
}
9090

9191
// eslint-disable-next-line @typescript-eslint/no-explicit-any
92-
private arrayEqual(a1: any[], a2: any[]): boolean {
92+
private arrayEqual(a1: Array<any>, a2: Array<any>): boolean {
9393
if (a1.length !== a2.length) {
9494
return false;
9595
}
96-
for (let index = 0; index < a1.length; index++) {
97-
const element = a1[index];
96+
for (const [index, element] of a1.entries()) {
9897
if (element !== a2[index]) {
9998
return false;
10099
}
@@ -103,12 +102,11 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
103102
}
104103

105104
// eslint-disable-next-line @typescript-eslint/no-explicit-any
106-
private arrayChild(a1: any[], a2: any[]): boolean {
105+
private arrayChild(a1: Array<any>, a2: Array<any>): boolean {
107106
if (a1.length - a2.length !== 1) {
108107
return false;
109108
}
110-
for (let index = 0; index < a2.length; index++) {
111-
const element = a2[index];
109+
for (const [index, element] of a2.entries()) {
112110
if (element !== a1[index]) {
113111
return false;
114112
}
@@ -117,7 +115,7 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
117115
}
118116

119117
private getResultTree(
120-
suiteResult: AssertionResult[],
118+
suiteResult: Array<AssertionResult>,
121119
testPath: string,
122120
suitePerf: PerformanceInfo
123121
): ResultTree {
@@ -127,23 +125,18 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
127125
passed: true,
128126
performanceInfo: suitePerf
129127
};
130-
const branches: string[][] = [];
128+
const branches: Array<Array<string>> = [];
131129
for (const element of suiteResult) {
132130
if (element.ancestorTitles.length === 0) {
133-
let passed = true;
134131
if (element.status === 'failed') {
135132
root.passed = false;
136-
passed = false;
137-
} else if (element.status !== 'passed') {
138-
throw new Error(
139-
`Expected status to be 'failed' or 'passed', got ${element.status}`
140-
);
141133
}
134+
const duration = element.duration || 1;
142135
root.children.push({
143136
children: [],
144-
duration: Math.max(element.duration || 0, 1),
137+
duration,
145138
name: element.title,
146-
passed
139+
status: element.status
147140
});
148141
} else {
149142
let alreadyInserted = false;
@@ -169,27 +162,29 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
169162
}
170163

171164
private getResultChildren(
172-
suiteResult: AssertionResult[],
173-
ancestors: string[]
174-
): ResultTreeNode | ResultTreeLeaf {
175-
const node: ResultTreeNode | ResultTreeLeaf = {
165+
suiteResult: Array<AssertionResult>,
166+
ancestors: Array<string>
167+
): ResultTreeNode {
168+
const node: ResultTreeNode = {
176169
children: [],
177-
name: ancestors[ancestors.length - 1],
170+
name: ancestors.at(-1) || '',
178171
passed: true
179172
};
180-
const branches: string[][] = [];
173+
const branches: Array<Array<string>> = [];
181174
for (const element of suiteResult) {
182-
let passed = true;
175+
let duration = element.duration;
176+
if (!duration || Number.isNaN(duration)) {
177+
duration = 1;
178+
}
183179
if (this.arrayEqual(element.ancestorTitles, ancestors)) {
184180
if (element.status === 'failed') {
185181
node.passed = false;
186-
passed = false;
187182
}
188183
node.children.push({
189184
children: [],
190-
duration: Math.max(element.duration || 0, 1),
185+
duration,
191186
name: element.title,
192-
passed
187+
status: element.status
193188
});
194189
} else if (
195190
this.arrayChild(
@@ -234,15 +229,15 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
234229
perfMs = ` (${resultTree.performanceInfo.runtime} ms)`;
235230
}
236231
if (resultTree.passed) {
237-
core.startGroup(
232+
this.startGroup(
238233
`${chalk.bold.green.inverse('PASS')} ${resultTree.name}${perfMs}`
239234
);
240235
for (const child of resultTree.children) {
241236
this.recursivePrintResultTree(child, true, 1);
242237
}
243-
core.endGroup();
238+
this.endGroup();
244239
} else {
245-
core.info(
240+
this.log(
246241
` ${chalk.bold.red.inverse('FAIL')} ${resultTree.name}${perfMs}`
247242
);
248243
for (const child of resultTree.children) {
@@ -257,37 +252,53 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
257252
depth: number
258253
): void {
259254
if (resultTree.children.length === 0) {
260-
const leaf = resultTree as ResultTreeLeaf;
255+
if (!('duration' in resultTree)) {
256+
throw new Error('Expected a leaf. Got a node.');
257+
}
261258
let numberSpaces = depth;
262259
if (!alreadyGrouped) {
263260
numberSpaces++;
264261
}
265262
const spaces = ' '.repeat(numberSpaces);
266263
let resultSymbol;
267-
if (leaf.passed) {
268-
resultSymbol = chalk.green('\u2713');
269-
} else {
270-
resultSymbol = chalk.red('\u00D7');
264+
switch (resultTree.status) {
265+
case 'passed':
266+
resultSymbol = chalk.green(ICONS.success);
267+
break;
268+
case 'failed':
269+
resultSymbol = chalk.red(ICONS.failed);
270+
break;
271+
case 'todo':
272+
resultSymbol = chalk.magenta(ICONS.todo);
273+
break;
274+
case 'pending':
275+
case 'skipped':
276+
resultSymbol = chalk.yellow(ICONS.pending);
277+
break;
271278
}
272-
core.info(`${spaces + resultSymbol} ${leaf.name} (${leaf.duration} ms)`);
279+
this.log(
280+
`${spaces}${resultSymbol} ${resultTree.name} (${resultTree.duration} ms)`
281+
);
273282
} else {
274-
const node = resultTree as ResultTreeNode;
275-
if (node.passed) {
283+
if (!('passed' in resultTree)) {
284+
throw new Error('Expected a node. Got a leaf');
285+
}
286+
if (resultTree.passed) {
276287
if (alreadyGrouped) {
277-
core.info(' '.repeat(depth) + node.name);
278-
for (const child of node.children) {
288+
this.log(' '.repeat(depth) + resultTree.name);
289+
for (const child of resultTree.children) {
279290
this.recursivePrintResultTree(child, true, depth + 1);
280291
}
281292
} else {
282-
core.startGroup(' '.repeat(depth) + node.name);
283-
for (const child of node.children) {
293+
this.startGroup(' '.repeat(depth) + resultTree.name);
294+
for (const child of resultTree.children) {
284295
this.recursivePrintResultTree(child, true, depth + 1);
285296
}
286-
core.endGroup();
297+
this.endGroup();
287298
}
288299
} else {
289-
core.info(' '.repeat(depth + 1) + node.name);
290-
for (const child of node.children) {
300+
this.log(' '.repeat(depth + 1) + resultTree.name);
301+
for (const child of resultTree.children) {
291302
this.recursivePrintResultTree(child, false, depth + 1);
292303
}
293304
}
@@ -306,12 +317,27 @@ export default class GithubActionsReporter extends reporters.BaseReporter {
306317
testDir = testDir.replace(rootDir, '');
307318
testDir = testDir.slice(1, testDir.length);
308319
if (result.failureMessage) {
309-
written = true;
310-
core.startGroup(`Errors thrown in ${testDir}`);
311-
core.info(result.failureMessage);
312-
core.endGroup();
320+
if (!written) {
321+
this.log('');
322+
written = true;
323+
}
324+
this.startGroup(`Errors thrown in ${testDir}`);
325+
this.log(result.failureMessage);
326+
this.endGroup();
313327
}
314328
}
315329
return written;
316330
}
331+
332+
override log(message: string): void {
333+
core.info(message);
334+
}
335+
336+
private startGroup(title: string): void {
337+
core.startGroup(title);
338+
}
339+
340+
private endGroup(): void {
341+
core.endGroup();
342+
}
317343
}

0 commit comments

Comments
 (0)