Skip to content

Commit ce4141a

Browse files
committed
added tests to handle case when stack/cause throw error
1 parent 5f76c1e commit ce4141a

8 files changed

+177
-84
lines changed

lib/internal/test_runner/reporter/spec.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ class SpecReporter extends Transform {
9191
ArrayPrototypeShift(this.#reported);
9292
return `${prefix}${indent}${color}${symbols['arrow:right']}${white}${title}\n\n`;
9393
}
94-
const error = this.#formatError(data.details?.error, indent);
94+
let error = '';
95+
try {
96+
error = this.#formatError(data.details?.error, indent);
97+
} catch (err) {
98+
error = this.#formatError(err, indent);
99+
}
95100
if (skippedSubtest) {
96101
color = gray;
97102
symbol = symbols['hyphen:minus'];

lib/internal/test_runner/reporter/tap.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
ArrayPrototypeSome,
77
NumberPrototypeToFixed,
88
ObjectEntries,
9+
ObjectPrototypeHasOwnProperty,
910
RegExpPrototypeSymbolReplace,
1011
SafeMap,
1112
StringPrototypeRepeat,
@@ -219,11 +220,7 @@ function jsToYaml(indent, name, value) {
219220
// If the ERR_TEST_FAILURE came from an error provided by user code,
220221
// then try to unwrap the original error message and stack.
221222
if (code === 'ERR_TEST_FAILURE' && kUnwrapErrors.has(failureType)) {
222-
if (cause?.cause) {
223-
errStack = inspect(cause);
224-
} else {
225-
errStack = cause?.stack ?? errStack;
226-
}
223+
errStack = getErrorStack(cause, errStack);
227224
errCode = cause?.code ?? errCode;
228225
errName = cause?.name ?? errName;
229226
if (isAssertionLike(cause)) {
@@ -263,7 +260,7 @@ function jsToYaml(indent, name, value) {
263260
const processed = tapEscape(RegExpPrototypeSymbolReplace(
264261
kFrameStartRegExp,
265262
ArrayPrototypeJoin(
266-
StringPrototypeSplit(frame, ' at'),
263+
StringPrototypeSplit(frame, ' at'),
267264
'',
268265
),
269266
'',
@@ -293,4 +290,15 @@ function isAssertionLike(value) {
293290
return value && typeof value === 'object' && 'expected' in value && 'actual' in value;
294291
}
295292

293+
function getErrorStack(cause, errStack) {
294+
try {
295+
if (cause !== null && ObjectPrototypeHasOwnProperty(cause, 'cause')) {
296+
return inspect(cause);
297+
}
298+
return cause?.stack ?? errStack;
299+
} catch (err) {
300+
return inspect(err);
301+
}
302+
}
303+
296304
module.exports = tapReporter;

test/message/test_runner_describe_it.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ not ok 56 - describe async throw fails
563563
error: 'test timed out after 5ms'
564564
code: 'ERR_TEST_FAILURE'
565565
stack: |-
566-
async Promise.all (index 0)
566+
async Promise.all (index 0)
567567
...
568568
# Subtest: timed out callback test
569569
not ok 2 - timed out callback test

test/message/test_runner_output.js

+12
Original file line numberDiff line numberDiff line change
@@ -417,3 +417,15 @@ test('should handle primitive, undefined and null cause', () => {
417417
throw new Error('foo', { cause: null });
418418
});
419419
});
420+
421+
test('should handle case when cause throw', () => {
422+
const error = new Error();
423+
Reflect.defineProperty(error, 'cause', { get() { throw new Error('bar'); } });
424+
throw error;
425+
});
426+
427+
test('should handle case when stack throw', () => {
428+
const error = new Error();
429+
Reflect.defineProperty(error, 'stack', { get() { throw new Error('bar'); } });
430+
throw error;
431+
});

test/message/test_runner_output.out

+56-29
Original file line numberDiff line numberDiff line change
@@ -632,15 +632,15 @@ not ok 65 - should print error cause
632632
error: 'foo'
633633
code: 'ERR_TEST_FAILURE'
634634
stack: |-
635+
*
636+
*
637+
*
638+
*
639+
[cause]: Error: bar
635640
*
636641
*
637642
*
638643
*
639-
[cause]: Error: bar
640-
*
641-
*
642-
*
643-
*
644644
...
645645
# Subtest: should print error cause for nested errors
646646
not ok 66 - should print error cause for nested errors
@@ -650,20 +650,20 @@ not ok 66 - should print error cause for nested errors
650650
error: 'a'
651651
code: 'ERR_TEST_FAILURE'
652652
stack: |-
653+
*
654+
*
655+
*
656+
*
657+
[cause]: Error: b
653658
*
654659
*
655660
*
656661
*
657-
[cause]: Error: b
662+
[cause]: Error: c
658663
*
659664
*
660665
*
661666
*
662-
[cause]: Error: c
663-
*
664-
*
665-
*
666-
*
667667
[cause]: [Error]
668668
...
669669
# Subtest: should handle cycles in error
@@ -674,20 +674,20 @@ not ok 67 - should handle cycles in error
674674
error: 'b'
675675
code: 'ERR_TEST_FAILURE'
676676
stack: |-
677+
*
678+
*
679+
*
680+
*
681+
[cause]: Error: c
677682
*
678683
*
679684
*
680685
*
681-
[cause]: Error: c
686+
[cause]: Error: d
682687
*
683688
*
684689
*
685690
*
686-
[cause]: Error: d
687-
*
688-
*
689-
*
690-
*
691691
[cause]: [Circular *1]
692692
...
693693
# Subtest: should handle primitive, undefined and null cause
@@ -699,10 +699,10 @@ not ok 67 - should handle cycles in error
699699
error: 'foo'
700700
code: 'ERR_TEST_FAILURE'
701701
stack: |-
702-
*
703-
*
704-
*
705-
*
702+
*
703+
*
704+
*
705+
*
706706
[cause]: 'something went wrong'
707707
...
708708
# Subtest: undefined cause
@@ -713,10 +713,11 @@ not ok 67 - should handle cycles in error
713713
error: 'foo'
714714
code: 'ERR_TEST_FAILURE'
715715
stack: |-
716-
*
717-
*
718-
*
719-
*
716+
*
717+
*
718+
*
719+
*
720+
[cause]: undefined
720721
...
721722
# Subtest: null cause
722723
not ok 3 - null cause
@@ -734,8 +735,34 @@ not ok 68 - should handle primitive, undefined and null cause
734735
error: '3 subtests failed'
735736
code: 'ERR_TEST_FAILURE'
736737
...
738+
# Subtest: should handle case when cause throw
739+
not ok 69 - should handle case when cause throw
740+
---
741+
duration_ms: *
742+
failureType: 'testCodeFailure'
743+
error: ''
744+
code: 'ERR_TEST_FAILURE'
745+
stack: |-
746+
*
747+
*
748+
*
749+
*
750+
...
751+
# Subtest: should handle case when stack throw
752+
not ok 70 - should handle case when stack throw
753+
---
754+
duration_ms: *
755+
failureType: 'testCodeFailure'
756+
error: ''
757+
code: 'ERR_TEST_FAILURE'
758+
stack: |-
759+
*
760+
*
761+
*
762+
*
763+
...
737764
# Subtest: invalid subtest fail
738-
not ok 69 - invalid subtest fail
765+
not ok 71 - invalid subtest fail
739766
---
740767
duration_ms: *
741768
failureType: 'parentAlreadyFinished'
@@ -744,17 +771,17 @@ not ok 69 - invalid subtest fail
744771
stack: |-
745772
*
746773
...
747-
1..69
774+
1..71
748775
# 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.
749776
# 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.
750777
# Warning: A resource generated asynchronous activity after the test ended. This activity created the error "Error: uncaught from outside of a test" which triggered an uncaughtException event, caught by the test runner.
751778
# 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.
752779
# 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.
753780
# 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.
754781
# 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.
755-
# tests 69
782+
# tests 71
756783
# pass 27
757-
# fail 25
784+
# fail 27
758785
# cancelled 2
759786
# skipped 10
760787
# todo 5

0 commit comments

Comments
 (0)