diff --git a/CHANGELOG.md b/CHANGELOG.md index da217d7ac122..cda3cd808e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * `[jest-runtime]` Move `babel-core` to peer dependencies so it works with Babel 7 ([#4557](https://github.com/facebook/jest/pull/4557)) * `[jest-util]` Fix `runOnlyPendingTimers` for `setTimeout` inside `setImmediate` ([#4608](https://github.com/facebook/jest/pull/4608)) * `[jest-message-util]` Always remove node internals from stacktraces ([#4695](https://github.com/facebook/jest/pull/4695)) +* `[pretty-format]` Show exception stack trace when errors are thrown by plugins ([#4738](https://github.com/facebook/jest/pull/4738)) ### Features * `[jest-environment-*]` [**BREAKING**] Add Async Test Environment APIs, dispose is now teardown ([#4506](https://github.com/facebook/jest/pull/4506)) diff --git a/packages/pretty-format/src/__tests__/pretty_format.test.js b/packages/pretty-format/src/__tests__/pretty_format.test.js index 28ea1dd05b94..c9817caedb91 100644 --- a/packages/pretty-format/src/__tests__/pretty_format.test.js +++ b/packages/pretty-format/src/__tests__/pretty_format.test.js @@ -549,6 +549,57 @@ describe('prettyFormat()', () => { }).toThrow(); }); + it('throws the plugin error stack when test throws an error', () => { + const error = new Error(); + const options = { + plugins: [ + { + print: () => '', + test() { + throw error; + }, + }, + ], + }; + expect(() => { + prettyFormat('', options); + }).toThrow(error.stack); + }); + + it('throws the plugin error stack when print throws an error', () => { + const error = new Error(); + const options = { + plugins: [ + { + print: () => { + throw error; + }, + test: () => true, + }, + ], + }; + expect(() => { + prettyFormat('', options); + }).toThrow(error.stack); + }); + + it('throws the plugin error stack when serialize throws an error', () => { + const error = new Error(); + const options = { + plugins: [ + { + serialize: () => { + throw error; + }, + test: () => true, + }, + ], + }; + expect(() => { + prettyFormat('', options); + }).toThrow(error.stack); + }); + it('supports plugins with deeply nested arrays (#24)', () => { const val = [[1, 2], [3, 4]]; expect( diff --git a/packages/pretty-format/src/index.js b/packages/pretty-format/src/index.js index 35a591c90da8..d62110c61571 100644 --- a/packages/pretty-format/src/index.js +++ b/packages/pretty-format/src/index.js @@ -240,25 +240,32 @@ function printPlugin( depth: number, refs: Refs, ): string { - const printed = plugin.serialize - ? plugin.serialize(val, config, indentation, depth, refs, printer) - : plugin.print( - val, - valChild => printer(valChild, config, indentation, depth, refs), - str => { - const indentationNext = indentation + config.indent; - return ( - indentationNext + - str.replace(NEWLINE_REGEXP, '\n' + indentationNext) - ); - }, - { - edgeSpacing: config.spacingOuter, - min: config.min, - spacing: config.spacingInner, - }, - config.colors, - ); + let printed; + + try { + printed = plugin.serialize + ? plugin.serialize(val, config, indentation, depth, refs, printer) + : plugin.print( + val, + valChild => printer(valChild, config, indentation, depth, refs), + str => { + const indentationNext = indentation + config.indent; + return ( + indentationNext + + str.replace(NEWLINE_REGEXP, '\n' + indentationNext) + ); + }, + { + edgeSpacing: config.spacingOuter, + min: config.min, + spacing: config.spacingInner, + }, + config.colors, + ); + } catch (error) { + throw new Error(error.stack); + } + if (typeof printed !== 'string') { throw new Error( `pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`, @@ -269,8 +276,12 @@ function printPlugin( function findPlugin(plugins: Plugins, val: any) { for (let p = 0; p < plugins.length; p++) { - if (plugins[p].test(val)) { - return plugins[p]; + try { + if (plugins[p].test(val)) { + return plugins[p]; + } + } catch (error) { + throw new Error(error.stack); } }