Skip to content

Commit f0e5658

Browse files
committed
test: fix test runner does not print error cause
1 parent 85c8b78 commit f0e5658

7 files changed

+264
-18
lines changed

lib/internal/test_runner/reporter/tap.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ const {
1010
StringPrototypeReplaceAll,
1111
StringPrototypeSplit,
1212
StringPrototypeRepeat,
13+
StringPrototypeStartsWith
1314
} = primordials;
1415
const { inspectWithNoCustomRetry } = require('internal/errors');
1516
const { isError, kEmptyObject } = require('internal/util');
1617
const { relative } = require('path');
18+
const util = require('util');
1719
const kDefaultIndent = ' '; // 4 spaces
1820
const kFrameStartRegExp = /^ {4}at /;
1921
const kLineBreakRegExp = /\n|\r\n/;
@@ -234,9 +236,27 @@ function jsToYaml(indent, name, value) {
234236
}
235237
}
236238

237-
if (typeof errStack === 'string') {
238-
const frames = [];
239+
const frames = [];
239240

241+
if (cause?.cause) {
242+
const errCause = util.inspect(cause).split('\n').slice(1)
243+
.filter((line) => !StringPrototypeStartsWith(line.trim(), '...') && line)
244+
.join('\n');
245+
ArrayPrototypeForEach(
246+
StringPrototypeSplit(errCause, kLineBreakRegExp),
247+
(frame) => {
248+
const processed = RegExpPrototypeSymbolReplace(
249+
kFrameStartRegExp,
250+
frame,
251+
''
252+
);
253+
254+
if (processed.length > 0) {
255+
ArrayPrototypePush(frames, processed);
256+
}
257+
}
258+
);
259+
} else if (typeof errStack === 'string') {
240260
ArrayPrototypeForEach(
241261
StringPrototypeSplit(errStack, kLineBreakRegExp),
242262
(frame) => {
@@ -251,13 +271,13 @@ function jsToYaml(indent, name, value) {
251271
}
252272
}
253273
);
274+
}
254275

255-
if (frames.length > 0) {
256-
const frameDelimiter = `\n${indent} `;
276+
if (frames.length > 0) {
277+
const frameDelimiter = `\n${indent} `;
257278

258-
result += `${indent} stack: |-${frameDelimiter}`;
259-
result += `${ArrayPrototypeJoin(frames, frameDelimiter)}\n`;
260-
}
279+
result += `${indent} stack: |-${frameDelimiter}`;
280+
result += `${ArrayPrototypeJoin(frames, frameDelimiter)}\n`;
261281
}
262282
}
263283

test/message/test_runner_describe_it.out

+6-2
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ not ok 13 - async assertion fail
113113
failureType: 'testCodeFailure'
114114
error: |-
115115
Expected values to be strictly equal:
116-
116+
117117
true !== false
118-
118+
119119
code: 'ERR_ASSERTION'
120120
expected: false
121121
actual: true
@@ -403,6 +403,10 @@ not ok 48 - callback called twice in future tick
403403
code: 'ERR_TEST_FAILURE'
404404
stack: |-
405405
*
406+
*
407+
*
408+
*
409+
*
406410
...
407411
# Subtest: callback async throw
408412
not ok 49 - callback async throw

test/message/test_runner_output.js

+14
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,17 @@ test('unfinished test with unhandledRejection', async () => {
383383
setTimeout(() => Promise.reject(new Error('bar')));
384384
});
385385
});
386+
387+
test('should print error cause', () => {
388+
throw new Error('foo', {cause: new Error('bar')});
389+
});
390+
391+
test('should print error cause for nested errors', () => {
392+
throw new Error('a', { cause: new Error('b', { cause: new Error('c', { cause: new Error('d', { cause: new Error('e') }) }) }) })
393+
});
394+
395+
test("should handle cycles in error", () => {
396+
const outer = new Error('b', { cause: null });
397+
outer.cause = new Error('c', { cause: new Error('d', { cause: outer }) });
398+
throw outer;
399+
});

test/message/test_runner_output.out

+78-4
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,10 @@ not ok 50 - callback called twice in future tick
447447
code: 'ERR_TEST_FAILURE'
448448
stack: |-
449449
*
450+
*
451+
*
452+
*
453+
*
450454
...
451455
# Subtest: callback async throw
452456
not ok 51 - callback async throw
@@ -620,8 +624,78 @@ not ok 64 - unfinished test with unhandledRejection
620624
*
621625
*
622626
...
627+
# Subtest: should print error cause
628+
not ok 65 - should print error cause
629+
---
630+
duration_ms: *
631+
failureType: 'testCodeFailure'
632+
error: 'foo'
633+
code: 'ERR_TEST_FAILURE'
634+
stack: |-
635+
*
636+
*
637+
*
638+
*
639+
*
640+
*
641+
*
642+
*
643+
*
644+
*
645+
*
646+
*
647+
*
648+
...
649+
# Subtest: should print error cause for nested errors
650+
not ok 66 - should print error cause for nested errors
651+
---
652+
duration_ms: *
653+
failureType: 'testCodeFailure'
654+
error: 'a'
655+
code: 'ERR_TEST_FAILURE'
656+
stack: |-
657+
*
658+
*
659+
*
660+
*
661+
*
662+
*
663+
*
664+
*
665+
*
666+
*
667+
*
668+
*
669+
*
670+
*
671+
*
672+
...
673+
# Subtest: should handle cycles in error
674+
not ok 67 - should handle cycles in error
675+
---
676+
duration_ms: *
677+
failureType: 'testCodeFailure'
678+
error: 'b'
679+
code: 'ERR_TEST_FAILURE'
680+
stack: |-
681+
*
682+
*
683+
*
684+
*
685+
*
686+
*
687+
*
688+
*
689+
*
690+
*
691+
*
692+
*
693+
*
694+
*
695+
*
696+
...
623697
# Subtest: invalid subtest fail
624-
not ok 65 - invalid subtest fail
698+
not ok 68 - invalid subtest fail
625699
---
626700
duration_ms: *
627701
failureType: 'parentAlreadyFinished'
@@ -630,16 +704,16 @@ not ok 65 - invalid subtest fail
630704
stack: |-
631705
*
632706
...
633-
1..65
707+
1..68
634708
# Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
635709
# Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
636710
# Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event.
637711
# Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
638712
# Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: callback invoked multiple times" and would have caused the test to fail, but instead triggered an uncaughtException event.
639713
# Warning: Test "callback async throw after done" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from callback async throw after done" and would have caused the test to fail, but instead triggered an uncaughtException event.
640-
# tests 65
714+
# tests 68
641715
# pass 27
642-
# fail 21
716+
# fail 24
643717
# cancelled 2
644718
# skipped 10
645719
# todo 5

test/message/test_runner_output_cli.out

+76-2
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ TAP version 13
448448
code: 'ERR_TEST_FAILURE'
449449
stack: |-
450450
*
451+
*
452+
*
453+
*
454+
*
451455
...
452456
# Subtest: callback async throw
453457
not ok 51 - callback async throw
@@ -621,8 +625,78 @@ TAP version 13
621625
*
622626
*
623627
...
628+
# Subtest: should print error cause
629+
not ok 65 - should print error cause
630+
---
631+
duration_ms: *
632+
failureType: 'testCodeFailure'
633+
error: 'foo'
634+
code: 'ERR_TEST_FAILURE'
635+
stack: |-
636+
*
637+
*
638+
*
639+
*
640+
*
641+
*
642+
*
643+
*
644+
*
645+
*
646+
*
647+
*
648+
*
649+
...
650+
# Subtest: should print error cause for nested errors
651+
not ok 66 - should print error cause for nested errors
652+
---
653+
duration_ms: *
654+
failureType: 'testCodeFailure'
655+
error: 'a'
656+
code: 'ERR_TEST_FAILURE'
657+
stack: |-
658+
*
659+
*
660+
*
661+
*
662+
*
663+
*
664+
*
665+
*
666+
*
667+
*
668+
*
669+
*
670+
*
671+
*
672+
*
673+
...
674+
# Subtest: should handle cycles in error
675+
not ok 67 - should handle cycles in error
676+
---
677+
duration_ms: *
678+
failureType: 'testCodeFailure'
679+
error: 'b'
680+
code: 'ERR_TEST_FAILURE'
681+
stack: |-
682+
*
683+
*
684+
*
685+
*
686+
*
687+
*
688+
*
689+
*
690+
*
691+
*
692+
*
693+
*
694+
*
695+
*
696+
*
697+
...
624698
# Subtest: invalid subtest fail
625-
not ok 65 - invalid subtest fail
699+
not ok 68 - invalid subtest fail
626700
---
627701
duration_ms: *
628702
failureType: 'parentAlreadyFinished'
@@ -631,7 +705,7 @@ TAP version 13
631705
stack: |-
632706
*
633707
...
634-
1..65
708+
1..68
635709
# Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
636710
# Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
637711
# Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
..XX...X..XXX.X.....
22
XXX.....X..X...X....
33
.........X...XXX.XX.
4-
.....XXXXXXX...XXXX
4+
.....XXXXXXX...XXXXX
5+
XX

test/message/test_runner_output_spec_reporter.out

+61-2
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,65 @@
262262
*
263263
*
264264

265+
should print error cause (*ms)
266+
Error: foo
267+
*
268+
*
269+
*
270+
*
271+
*
272+
*
273+
*
274+
*
275+
*
276+
*
277+
*
278+
*
279+
*
280+
*
281+
282+
should print error cause for nested errors (*ms)
283+
Error: a
284+
*
285+
*
286+
*
287+
*
288+
*
289+
*
290+
*
291+
*
292+
*
293+
*
294+
*
295+
*
296+
*
297+
*
298+
*
299+
*
300+
*
301+
*
302+
303+
should handle cycles in error (*ms)
304+
<ref *1> Error: b
305+
*
306+
*
307+
*
308+
*
309+
*
310+
*
311+
*
312+
*
313+
*
314+
*
315+
*
316+
*
317+
*
318+
*
319+
*
320+
*
321+
*
322+
*
323+
265324
invalid subtest fail (*ms)
266325
'test could not be started because its parent finished'
267326

@@ -271,9 +330,9 @@
271330
Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event.
272331
Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: callback invoked multiple times" and would have caused the test to fail, but instead triggered an uncaughtException event.
273332
Warning: Test "callback async throw after done" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from callback async throw after done" and would have caused the test to fail, but instead triggered an uncaughtException event.
274-
tests 65
333+
tests 68
275334
pass 27
276-
fail 21
335+
fail 24
277336
cancelled 2
278337
skipped 10
279338
todo 5

0 commit comments

Comments
 (0)