Skip to content

Commit

Permalink
added tests to handle case when stack/cause throw error
Browse files Browse the repository at this point in the history
  • Loading branch information
pulkit-30 committed Mar 19, 2023
1 parent 5f76c1e commit ce4141a
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 84 deletions.
7 changes: 6 additions & 1 deletion lib/internal/test_runner/reporter/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ class SpecReporter extends Transform {
ArrayPrototypeShift(this.#reported);
return `${prefix}${indent}${color}${symbols['arrow:right']}${white}${title}\n\n`;
}
const error = this.#formatError(data.details?.error, indent);
let error = '';
try {
error = this.#formatError(data.details?.error, indent);
} catch (err) {
error = this.#formatError(err, indent);
}
if (skippedSubtest) {
color = gray;
symbol = symbols['hyphen:minus'];
Expand Down
20 changes: 14 additions & 6 deletions lib/internal/test_runner/reporter/tap.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
ArrayPrototypeSome,
NumberPrototypeToFixed,
ObjectEntries,
ObjectPrototypeHasOwnProperty,
RegExpPrototypeSymbolReplace,
SafeMap,
StringPrototypeRepeat,
Expand Down Expand Up @@ -219,11 +220,7 @@ function jsToYaml(indent, name, value) {
// If the ERR_TEST_FAILURE came from an error provided by user code,
// then try to unwrap the original error message and stack.
if (code === 'ERR_TEST_FAILURE' && kUnwrapErrors.has(failureType)) {
if (cause?.cause) {
errStack = inspect(cause);
} else {
errStack = cause?.stack ?? errStack;
}
errStack = getErrorStack(cause, errStack);
errCode = cause?.code ?? errCode;
errName = cause?.name ?? errName;
if (isAssertionLike(cause)) {
Expand Down Expand Up @@ -263,7 +260,7 @@ function jsToYaml(indent, name, value) {
const processed = tapEscape(RegExpPrototypeSymbolReplace(
kFrameStartRegExp,
ArrayPrototypeJoin(
StringPrototypeSplit(frame, ' at'),
StringPrototypeSplit(frame, ' at'),
'',
),
'',
Expand Down Expand Up @@ -293,4 +290,15 @@ function isAssertionLike(value) {
return value && typeof value === 'object' && 'expected' in value && 'actual' in value;
}

function getErrorStack(cause, errStack) {
try {
if (cause !== null && ObjectPrototypeHasOwnProperty(cause, 'cause')) {
return inspect(cause);
}
return cause?.stack ?? errStack;
} catch (err) {
return inspect(err);
}
}

module.exports = tapReporter;
2 changes: 1 addition & 1 deletion test/message/test_runner_describe_it.out
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ not ok 56 - describe async throw fails
error: 'test timed out after 5ms'
code: 'ERR_TEST_FAILURE'
stack: |-
async Promise.all (index 0)
async Promise.all (index 0)
...
# Subtest: timed out callback test
not ok 2 - timed out callback test
Expand Down
12 changes: 12 additions & 0 deletions test/message/test_runner_output.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,15 @@ test('should handle primitive, undefined and null cause', () => {
throw new Error('foo', { cause: null });
});
});

test('should handle case when cause throw', () => {
const error = new Error();
Reflect.defineProperty(error, 'cause', { get() { throw new Error('bar'); } });
throw error;
});

test('should handle case when stack throw', () => {
const error = new Error();
Reflect.defineProperty(error, 'stack', { get() { throw new Error('bar'); } });
throw error;
});
85 changes: 56 additions & 29 deletions test/message/test_runner_output.out
Original file line number Diff line number Diff line change
Expand Up @@ -632,15 +632,15 @@ not ok 65 - should print error cause
error: 'foo'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
[cause]: Error: bar
*
*
*
*
[cause]: Error: bar
*
*
*
*
...
# Subtest: should print error cause for nested errors
not ok 66 - should print error cause for nested errors
Expand All @@ -650,20 +650,20 @@ not ok 66 - should print error cause for nested errors
error: 'a'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
[cause]: Error: b
*
*
*
*
[cause]: Error: b
[cause]: Error: c
*
*
*
*
[cause]: Error: c
*
*
*
*
[cause]: [Error]
...
# Subtest: should handle cycles in error
Expand All @@ -674,20 +674,20 @@ not ok 67 - should handle cycles in error
error: 'b'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
[cause]: Error: c
*
*
*
*
[cause]: Error: c
[cause]: Error: d
*
*
*
*
[cause]: Error: d
*
*
*
*
[cause]: [Circular *1]
...
# Subtest: should handle primitive, undefined and null cause
Expand All @@ -699,10 +699,10 @@ not ok 67 - should handle cycles in error
error: 'foo'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
*
*
*
*
[cause]: 'something went wrong'
...
# Subtest: undefined cause
Expand All @@ -713,10 +713,11 @@ not ok 67 - should handle cycles in error
error: 'foo'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
*
*
*
*
[cause]: undefined
...
# Subtest: null cause
not ok 3 - null cause
Expand All @@ -734,8 +735,34 @@ not ok 68 - should handle primitive, undefined and null cause
error: '3 subtests failed'
code: 'ERR_TEST_FAILURE'
...
# Subtest: should handle case when cause throw
not ok 69 - should handle case when cause throw
---
duration_ms: *
failureType: 'testCodeFailure'
error: ''
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
...
# Subtest: should handle case when stack throw
not ok 70 - should handle case when stack throw
---
duration_ms: *
failureType: 'testCodeFailure'
error: ''
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
...
# Subtest: invalid subtest fail
not ok 69 - invalid subtest fail
not ok 71 - invalid subtest fail
---
duration_ms: *
failureType: 'parentAlreadyFinished'
Expand All @@ -744,17 +771,17 @@ not ok 69 - invalid subtest fail
stack: |-
*
...
1..69
1..71
# 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.
# 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.
# 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.
# 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.
# 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.
# 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.
# 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.
# tests 69
# tests 71
# pass 27
# fail 25
# fail 27
# cancelled 2
# skipped 10
# todo 5
Expand Down
Loading

0 comments on commit ce4141a

Please sign in to comment.