diff --git a/lib/assert.js b/lib/assert.js index 9e9d78046..2130b36c9 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -36,6 +36,7 @@ class AssertionError extends Error { this.assertion = opts.assertion; this.fixedSource = opts.fixedSource; this.improperUsage = opts.improperUsage || false; + this.actualStack = opts.actualStack; this.operator = opts.operator; this.values = opts.values || []; @@ -147,11 +148,14 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s }); } + const actualStack = actual.stack; + if (hasOwnProperty(expectations, 'is') && actual !== expectations.is) { throw new AssertionError({ assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected to be strictly equal to:', expectations.is) @@ -164,6 +168,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected instance of:', expectations.instanceOf) @@ -176,6 +181,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected name to equal:', expectations.name) @@ -188,6 +194,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected message to equal:', expectations.message) @@ -200,6 +207,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected message to match:', expectations.message) @@ -212,6 +220,7 @@ function assertExpectations({assertion, actual, expectations, message, prefix, s assertion, message, stack, + actualStack, values: [ formatWithLabel(`${prefix} unexpected exception:`, actual), formatWithLabel('Expected code to equal:', expectations.code) @@ -433,6 +442,7 @@ function wrapAssertions(callbacks) { fail(this, new AssertionError({ assertion: 'throwsAsync', message, + actualStack: actual.stack, values: [formatWithLabel('Function threw synchronously. Use `t.throws()` instead:', actual)] })); return Promise.resolve(); @@ -467,6 +477,7 @@ function wrapAssertions(callbacks) { fail(this, new AssertionError({ assertion: 'notThrows', message, + actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); return; @@ -493,7 +504,7 @@ function wrapAssertions(callbacks) { throw new AssertionError({ assertion: 'notThrowsAsync', message, - stack, + actualStack: stack, values: [formatWithLabel(`${wasReturned ? 'Returned promise' : 'Promise'} rejected with:`, reason)] }); }); @@ -513,6 +524,7 @@ function wrapAssertions(callbacks) { fail(this, new AssertionError({ assertion: 'notThrowsAsync', message, + actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); return Promise.resolve(); diff --git a/lib/serialize-error.js b/lib/serialize-error.js index ef07cb12b..c18fef8aa 100644 --- a/lib/serialize-error.js +++ b/lib/serialize-error.js @@ -60,6 +60,10 @@ function trySerializeError(err, shouldBeautifyStack) { stack }; + if (err.actualStack) { + retval.stack = shouldBeautifyStack ? beautifyStack(err.actualStack) : err.actualStack; + } + if (retval.avaAssertionError) { retval.improperUsage = err.improperUsage; retval.message = err.message; diff --git a/test/fixture/report/regular/traces-in-t-throws.js b/test/fixture/report/regular/traces-in-t-throws.js new file mode 100644 index 000000000..307ef606c --- /dev/null +++ b/test/fixture/report/regular/traces-in-t-throws.js @@ -0,0 +1,29 @@ +import test from '../../../..'; + +function throwError() { + throw new Error('uh-oh'); +} + +function returnRejectedPromise() { + return Promise.reject(new Error('uh-oh')); +} + +test('throws', t => { + t.throws(() => throwError(), TypeError); +}); + +test('notThrows', t => { + t.notThrows(() => throwError()); +}); + +test('notThrowsAsync', t => { + t.notThrowsAsync(() => throwError()); +}); + +test('throwsAsync', t => { + t.throwsAsync(() => throwError(), TypeError); +}); + +test('throwsAsync different error', t => { + return t.throwsAsync(returnRejectedPromise, TypeError); +}); diff --git a/test/reporters/mini.regular.log b/test/reporters/mini.regular.log index 990c2daac..0974b6767 100644 --- a/test/reporters/mini.regular.log +++ b/test/reporters/mini.regular.log @@ -15,26 +15,54 @@ 3 passed---tty-stream-chunk-separator ---tty-stream-chunk-separator +* traces-in-t-throws › throws + + 3 passed + 1 test failed---tty-stream-chunk-separator +---tty-stream-chunk-separator +* traces-in-t-throws › notThrows + + 3 passed + 2 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator +* traces-in-t-throws › notThrowsAsync + + 3 passed + 3 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator +* traces-in-t-throws › throwsAsync + + 3 passed + 4 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator +* traces-in-t-throws › throwsAsync different error + + 3 passed + 5 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator stdout -* uncaught-exception › passes +* traces-in-t-throws › throwsAsync different error - 3 passed---tty-stream-chunk-separator ----tty-stream-chunk-separator + 3 passed + 5 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator stderr -* uncaught-exception › passes +* traces-in-t-throws › throwsAsync different error - 3 passed---tty-stream-chunk-separator ----tty-stream-chunk-separator + 3 passed + 5 tests failed---tty-stream-chunk-separator +---tty-stream-chunk-separator * test › passes 4 passed + 5 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ----tty-stream-chunk-separator +---tty-stream-chunk-separator * test › fails 4 passed - 1 test failed + 6 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -42,7 +70,7 @@ stderr 4 passed 1 known failure - 1 test failed + 6 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -50,7 +78,7 @@ stderr 4 passed 1 known failure - 2 tests failed + 7 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -58,7 +86,7 @@ stderr 4 passed 1 known failure - 3 tests failed + 8 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -66,7 +94,7 @@ stderr 4 passed 1 known failure - 4 tests failed + 9 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -74,7 +102,7 @@ stderr 4 passed 1 known failure - 5 tests failed + 10 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -82,7 +110,7 @@ stderr 4 passed 1 known failure - 6 tests failed + 11 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -90,7 +118,7 @@ stderr 4 passed 1 known failure - 7 tests failed + 12 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -98,7 +126,7 @@ stderr 4 passed 1 known failure - 8 tests failed + 13 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -106,7 +134,7 @@ stderr 5 passed 1 known failure - 8 tests failed + 13 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -114,7 +142,7 @@ stderr 6 passed 1 known failure - 8 tests failed + 13 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator @@ -122,14 +150,14 @@ stderr 6 passed 1 known failure - 9 tests failed + 14 tests failed 1 skipped 1 todo---tty-stream-chunk-separator ---tty-stream-chunk-separator [?25h ✖ No tests found in test/fixture/report/regular/bad-test-chain.js - 9 tests failed + 14 tests failed 1 known failure 1 test skipped 1 test todo @@ -138,6 +166,113 @@ stderr test › known failure + traces-in-t-throws › throws + + ~/test/fixture/report/regular/traces-in-t-throws.js:12 + + 11: test('throws', t => { +  12: t.throws(() => throwError(), TypeError); + 13: }); + + Function threw unexpected exception: + + Error { + message: 'uh-oh', + } + + Expected instance of: + + Function TypeError {} + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:12:17) + throws (traces-in-t-throws.js:12:4) + + + + traces-in-t-throws › notThrows + + ~/test/fixture/report/regular/traces-in-t-throws.js:16 + + 15: test('notThrows', t => { +  16: t.notThrows(() => throwError()); + 17: }); + + Function threw: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:16:20) + notThrows (traces-in-t-throws.js:16:4) + + + + traces-in-t-throws › notThrowsAsync + + ~/test/fixture/report/regular/traces-in-t-throws.js:20 + + 19: test('notThrowsAsync', t => { +  20: t.notThrowsAsync(() => throwError()); + 21: }); + + Function threw: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:20:25) + notThrowsAsync (traces-in-t-throws.js:20:4) + + + + traces-in-t-throws › throwsAsync + + ~/test/fixture/report/regular/traces-in-t-throws.js:24 + + 23: test('throwsAsync', t => { +  24: t.throwsAsync(() => throwError(), TypeError); + 25: }); + + Function threw synchronously. Use `t.throws()` instead: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:24:22) + throwsAsync (traces-in-t-throws.js:24:4) + + + + traces-in-t-throws › throwsAsync different error + + ~/test/fixture/report/regular/traces-in-t-throws.js:28 + + 27: test('throwsAsync different error', t => { +  28: return t.throwsAsync(returnRejectedPromise, TypeError); + 29: }); + + Returned promise rejected with unexpected exception: + + Error { + message: 'uh-oh', + } + + Expected instance of: + + Function TypeError {} + + returnRejectedPromise (traces-in-t-throws.js:8:24) + throwsAsync (traces-in-t-throws.js:28:11) + + + test › fails ~/test/fixture/report/regular/test.js:12 diff --git a/test/reporters/tap.regular.log b/test/reporters/tap.regular.log index b16456c62..4c54560ff 100644 --- a/test/reporters/tap.regular.log +++ b/test/reporters/tap.regular.log @@ -46,21 +46,88 @@ not ok 8 - Error: Can't catch me # test/fixture/report/regular/uncaught-exception.js exited with a non-zero exit code: 1 not ok 9 - test/fixture/report/regular/uncaught-exception.js exited with a non-zero exit code: 1 ---tty-stream-chunk-separator +# traces-in-t-throws › throws +not ok 10 - traces-in-t-throws › throws + --- + name: AssertionError + assertion: throws + values: + 'Function threw unexpected exception:': |- + Error { + message: 'uh-oh', + } + 'Expected instance of:': 'Function TypeError {}' + at: 'throwError (traces-in-t-throws.js:4:8)' + ... +---tty-stream-chunk-separator +# traces-in-t-throws › notThrows +not ok 11 - traces-in-t-throws › notThrows + --- + name: AssertionError + assertion: notThrows + values: + 'Function threw:': |- + Error { + message: 'uh-oh', + } + at: 'throwError (traces-in-t-throws.js:4:8)' + ... +---tty-stream-chunk-separator +# traces-in-t-throws › notThrowsAsync +not ok 12 - traces-in-t-throws › notThrowsAsync + --- + name: AssertionError + assertion: notThrowsAsync + values: + 'Function threw:': |- + Error { + message: 'uh-oh', + } + at: 'throwError (traces-in-t-throws.js:4:8)' + ... +---tty-stream-chunk-separator +# traces-in-t-throws › throwsAsync +not ok 13 - traces-in-t-throws › throwsAsync + --- + name: AssertionError + assertion: throwsAsync + values: + 'Function threw synchronously. Use `t.throws()` instead:': |- + Error { + message: 'uh-oh', + } + at: 'throwError (traces-in-t-throws.js:4:8)' + ... +---tty-stream-chunk-separator +# traces-in-t-throws › throwsAsync different error +not ok 14 - traces-in-t-throws › throwsAsync different error + --- + name: AssertionError + assertion: throwsAsync + values: + 'Returned promise rejected with unexpected exception:': |- + Error { + message: 'uh-oh', + } + 'Expected instance of:': 'Function TypeError {}' + at: 'returnRejectedPromise (traces-in-t-throws.js:8:24)' + ... +---tty-stream-chunk-separator stdout ---tty-stream-chunk-separator stderr ---tty-stream-chunk-separator # test › skip -ok 10 - test › skip # SKIP +ok 15 - test › skip # SKIP ---tty-stream-chunk-separator # test › todo -not ok 11 - test › todo # TODO +not ok 16 - test › todo # TODO ---tty-stream-chunk-separator # test › passes -ok 12 - test › passes +ok 17 - test › passes ---tty-stream-chunk-separator # test › fails -not ok 13 - test › fails +not ok 18 - test › fails --- name: AssertionError message: Test failed via `t.fail()` @@ -69,10 +136,10 @@ not ok 13 - test › fails ... ---tty-stream-chunk-separator # test › known failure -ok 14 - test › known failure +ok 19 - test › known failure ---tty-stream-chunk-separator # test › no longer failing -not ok 15 - test › no longer failing +not ok 20 - test › no longer failing --- name: Error message: >- @@ -81,7 +148,7 @@ not ok 15 - test › no longer failing ... ---tty-stream-chunk-separator # test › logs -not ok 16 - test › logs +not ok 21 - test › logs * hello * world --- @@ -92,7 +159,7 @@ not ok 16 - test › logs ... ---tty-stream-chunk-separator # test › formatted -not ok 17 - test › formatted +not ok 22 - test › formatted --- name: AssertionError assertion: deepEqual @@ -104,7 +171,7 @@ not ok 17 - test › formatted ... ---tty-stream-chunk-separator # test › power-assert -not ok 18 - test › power-assert +not ok 23 - test › power-assert --- name: AssertionError assertion: falsy @@ -115,7 +182,7 @@ not ok 18 - test › power-assert ... ---tty-stream-chunk-separator # test › bad throws -not ok 19 - test › bad throws +not ok 24 - test › bad throws --- name: AssertionError message: Improper usage of `t.throws()` detected @@ -129,7 +196,7 @@ not ok 19 - test › bad throws ... ---tty-stream-chunk-separator # test › bad notThrows -not ok 20 - test › bad notThrows +not ok 25 - test › bad notThrows --- name: AssertionError message: Improper usage of `t.notThrows()` detected @@ -143,7 +210,7 @@ not ok 20 - test › bad notThrows ... ---tty-stream-chunk-separator # test › implementation throws non-error -not ok 21 - test › implementation throws non-error +not ok 26 - test › implementation throws non-error --- name: AssertionError message: Error thrown in test @@ -152,13 +219,13 @@ not ok 21 - test › implementation throws non-error ... ---tty-stream-chunk-separator # slow › slow -ok 22 - slow › slow +ok 27 - slow › slow ---tty-stream-chunk-separator # output-in-hook › passing test -ok 23 - output-in-hook › passing test +ok 28 - output-in-hook › passing test ---tty-stream-chunk-separator # output-in-hook › failing test -not ok 24 - output-in-hook › failing test +not ok 29 - output-in-hook › failing test --- name: AssertionError message: Test failed via `t.fail()` @@ -167,10 +234,10 @@ not ok 24 - output-in-hook › failing test ... ---tty-stream-chunk-separator -1..18 -# tests 17 +1..23 +# tests 22 # pass 7 # skip 1 -# fail 16 +# fail 21 ---tty-stream-chunk-separator diff --git a/test/reporters/verbose.regular.log b/test/reporters/verbose.regular.log index 7f497f495..6379a8493 100644 --- a/test/reporters/verbose.regular.log +++ b/test/reporters/verbose.regular.log @@ -49,6 +49,16 @@ ---tty-stream-chunk-separator ✖ test/fixture/report/regular/uncaught-exception.js exited with a non-zero exit code: 1 +---tty-stream-chunk-separator + ✖ traces-in-t-throws › throws +---tty-stream-chunk-separator + ✖ traces-in-t-throws › notThrows +---tty-stream-chunk-separator + ✖ traces-in-t-throws › notThrowsAsync +---tty-stream-chunk-separator + ✖ traces-in-t-throws › throwsAsync +---tty-stream-chunk-separator + ✖ traces-in-t-throws › throwsAsync different error ---tty-stream-chunk-separator stdout ---tty-stream-chunk-separator @@ -108,7 +118,7 @@ stderr ℹ afterAlways ---tty-stream-chunk-separator - 9 tests failed + 14 tests failed 1 known failure 1 test skipped 1 test todo @@ -117,6 +127,113 @@ stderr test › known failure + traces-in-t-throws › throws + + ~/test/fixture/report/regular/traces-in-t-throws.js:12 + + 11: test('throws', t => { +  12: t.throws(() => throwError(), TypeError); + 13: }); + + Function threw unexpected exception: + + Error { + message: 'uh-oh', + } + + Expected instance of: + + Function TypeError {} + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:12:17) + throws (traces-in-t-throws.js:12:4) + + + + traces-in-t-throws › notThrows + + ~/test/fixture/report/regular/traces-in-t-throws.js:16 + + 15: test('notThrows', t => { +  16: t.notThrows(() => throwError()); + 17: }); + + Function threw: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:16:20) + notThrows (traces-in-t-throws.js:16:4) + + + + traces-in-t-throws › notThrowsAsync + + ~/test/fixture/report/regular/traces-in-t-throws.js:20 + + 19: test('notThrowsAsync', t => { +  20: t.notThrowsAsync(() => throwError()); + 21: }); + + Function threw: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:20:25) + notThrowsAsync (traces-in-t-throws.js:20:4) + + + + traces-in-t-throws › throwsAsync + + ~/test/fixture/report/regular/traces-in-t-throws.js:24 + + 23: test('throwsAsync', t => { +  24: t.throwsAsync(() => throwError(), TypeError); + 25: }); + + Function threw synchronously. Use `t.throws()` instead: + + Error { + message: 'uh-oh', + } + + throwError (traces-in-t-throws.js:4:8) + throwError (traces-in-t-throws.js:24:22) + throwsAsync (traces-in-t-throws.js:24:4) + + + + traces-in-t-throws › throwsAsync different error + + ~/test/fixture/report/regular/traces-in-t-throws.js:28 + + 27: test('throwsAsync different error', t => { +  28: return t.throwsAsync(returnRejectedPromise, TypeError); + 29: }); + + Returned promise rejected with unexpected exception: + + Error { + message: 'uh-oh', + } + + Expected instance of: + + Function TypeError {} + + returnRejectedPromise (traces-in-t-throws.js:8:24) + throwsAsync (traces-in-t-throws.js:28:11) + + + test › fails ~/test/fixture/report/regular/test.js:12