From b5da70a3bc965a80eacf84caf5013e415eddcedd Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Mon, 6 May 2019 00:22:07 +0200 Subject: [PATCH 1/7] make watch plugin initialization errors look nice --- packages/jest-cli/src/cli/index.ts | 2 +- .../__snapshots__/watch.test.js.snap | 11 +++++++ .../jest-core/src/__tests__/watch.test.js | 32 ++++++++++++++++++- packages/jest-core/src/watch.ts | 25 +++++++++++---- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/packages/jest-cli/src/cli/index.ts b/packages/jest-cli/src/cli/index.ts index 800899896039..bb198ef8b35c 100644 --- a/packages/jest-cli/src/cli/index.ts +++ b/packages/jest-cli/src/cli/index.ts @@ -36,7 +36,7 @@ export async function run(maybeArgv?: Array, project?: Config.Path) { } catch (error) { clearLine(process.stderr); clearLine(process.stdout); - console.error(chalk.red(error.stack)); + console.error(chalk.red(error)); exit(1); throw error; } diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index 85d1828379c5..70a6fe598f14 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -50,6 +50,17 @@ Watch Usage ] `; +exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` +[Error: Failed to initialize watch plugin '/Users/timseckinger/proj/jest/packages/jest-core/src/__tests__/__fixtures__/plugin_path_throws': + + ● Test suite failed to run + + initialization failure + + at Object.jest.doMock [as user:/Users/timseckinger/proj/jest/packages/jest-core/src/__tests__/__fixtures__/plugin_path_throws:] (watch.test.js:584:15) +] +`; + exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = ` Array [ Array [ diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index 3d480a29fc23..8a9e7a0968f4 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -108,7 +108,12 @@ describe('Watch mode flows', () => { isInteractive = true; jest.doMock('jest-util/build/isInteractive', () => isInteractive); watch = require('../watch').default; - const config = {roots: [], testPathIgnorePatterns: [], testRegex: []}; + const config = { + rootDir: __dirname, + roots: [], + testPathIgnorePatterns: [], + testRegex: [], + }; pipe = {write: jest.fn()}; globalConfig = {watch: true}; hasteMapInstances = [{on: () => {}}]; @@ -571,6 +576,31 @@ describe('Watch mode flows', () => { }); }); + it('makes watch plugin initialization errors look nice', async () => { + const pluginPath = `${__dirname}/__fixtures__/plugin_path_throws`; + jest.doMock( + pluginPath, + () => { + throw new Error('initialization failure'); + }, + {virtual: true}, + ); + + await expect( + watch( + { + ...globalConfig, + rootDir: __dirname, + watchPlugins: [{config: {}, path: pluginPath}], + }, + contexts, + pipe, + hasteMapInstances, + stdin, + ), + ).rejects.toMatchSnapshot(); + }); + it.each` ok | option ${'✔︎'} | ${'bail'} diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 2efe8e05b165..5a4c9a891334 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -171,12 +171,25 @@ export default function watch( } for (const pluginWithConfig of globalConfig.watchPlugins) { - const ThirdPartyPlugin = require(pluginWithConfig.path); - const plugin: WatchPlugin = new ThirdPartyPlugin({ - config: pluginWithConfig.config, - stdin, - stdout: outputStream, - }); + let plugin: WatchPlugin; + try { + const ThirdPartyPlugin = require(pluginWithConfig.path); + plugin = new ThirdPartyPlugin({ + config: pluginWithConfig.config, + stdin, + stdout: outputStream, + }); + } catch (err) { + return Promise.reject( + new Error( + `Failed to initialize watch plugin '${ + pluginWithConfig.path + }':\n\n${formatExecError(err, contexts[0].config, { + noStackTrace: false, + })}`, + ), + ); + } checkForConflicts(watchPluginKeys, plugin, globalConfig); const hookSubscriber = hooks.getSubscriber(); From d055bdbda7930c4a3ed5f2c234ebefc9d44dbe49 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Mon, 6 May 2019 01:04:50 +0200 Subject: [PATCH 2/7] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 460ec7669bbd..b7fc6aa8f62c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes - `[babel-plugin-jest-hoist]` Expand list of whitelisted globals in global mocks ([#8429](https://github.com/facebook/jest/pull/8429) +- `[jest-core]` Make watch plugin initialization errors look nice ([#8422](https://github.com/facebook/jest/pull/8422)) ### Chore & Maintenance From e5f3e1b8d3566083ada70d6594f983611f5dfce2 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Mon, 6 May 2019 11:00:05 +0200 Subject: [PATCH 3/7] remove absolute path from snapshot --- .../src/__tests__/__snapshots__/watch.test.js.snap | 6 +++--- packages/jest-core/src/__tests__/watch.test.js | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index 70a6fe598f14..c60ed5424515 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -51,14 +51,14 @@ Watch Usage `; exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` -[Error: Failed to initialize watch plugin '/Users/timseckinger/proj/jest/packages/jest-core/src/__tests__/__fixtures__/plugin_path_throws': +"Failed to initialize watch plugin 'PATH_REPLACED': ● Test suite failed to run initialization failure - at Object.jest.doMock [as user:/Users/timseckinger/proj/jest/packages/jest-core/src/__tests__/__fixtures__/plugin_path_throws:] (watch.test.js:584:15) -] + at Object.jest.doMock [as user:PATH_REPLACED:] (watch.test.js:585:15) +" `; exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = ` diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index 8a9e7a0968f4..bbdff6d888e1 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -8,6 +8,7 @@ 'use strict'; +import path from 'path'; import chalk from 'chalk'; import TestWatcher from '../TestWatcher'; import {JestHook, KEYS} from 'jest-watcher'; @@ -586,8 +587,9 @@ describe('Watch mode flows', () => { {virtual: true}, ); - await expect( - watch( + expect.assertions(1); + try { + await watch( { ...globalConfig, rootDir: __dirname, @@ -597,8 +599,12 @@ describe('Watch mode flows', () => { pipe, hasteMapInstances, stdin, - ), - ).rejects.toMatchSnapshot(); + ); + } catch (err) { + expect( + err.message.split(path.resolve(pluginPath)).join('PATH_REPLACED'), + ).toMatchSnapshot(); + } }); it.each` From e2311509b5ff0dabb33bdc8be73db383c83b6cc0 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Mon, 6 May 2019 18:58:16 +0200 Subject: [PATCH 4/7] review feedback --- packages/jest-cli/src/cli/index.ts | 7 +++++- .../__fixtures__/watch_plugin_throws.js | 1 + .../__snapshots__/watch.test.js.snap | 8 +++---- .../jest-core/src/__tests__/watch.test.js | 23 ++++--------------- packages/jest-core/src/watch.ts | 20 ++++++++-------- 5 files changed, 27 insertions(+), 32 deletions(-) create mode 100644 packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js diff --git a/packages/jest-cli/src/cli/index.ts b/packages/jest-cli/src/cli/index.ts index bb198ef8b35c..ea73a76292bd 100644 --- a/packages/jest-cli/src/cli/index.ts +++ b/packages/jest-cli/src/cli/index.ts @@ -36,7 +36,12 @@ export async function run(maybeArgv?: Array, project?: Config.Path) { } catch (error) { clearLine(process.stderr); clearLine(process.stdout); - console.error(chalk.red(error)); + if (error.stack) { + console.error(chalk.red(error.stack)); + } else { + console.error(chalk.red(error)); + } + exit(1); throw error; } diff --git a/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js b/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js new file mode 100644 index 000000000000..2238a551d2d9 --- /dev/null +++ b/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js @@ -0,0 +1 @@ +throw new Error('initialization error'); diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index c60ed5424515..1ca0bd98bb58 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -51,14 +51,14 @@ Watch Usage `; exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` -"Failed to initialize watch plugin 'PATH_REPLACED': +[Error: Failed to initialize watch plugin 'packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws': ● Test suite failed to run - initialization failure + initialization error - at Object.jest.doMock [as user:PATH_REPLACED:] (watch.test.js:585:15) -" + at Object. (__fixtures__/watch_plugin_throws.js:1:7) +] `; exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = ` diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index bbdff6d888e1..358446807c64 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -8,7 +8,6 @@ 'use strict'; -import path from 'path'; import chalk from 'chalk'; import TestWatcher from '../TestWatcher'; import {JestHook, KEYS} from 'jest-watcher'; @@ -578,18 +577,10 @@ describe('Watch mode flows', () => { }); it('makes watch plugin initialization errors look nice', async () => { - const pluginPath = `${__dirname}/__fixtures__/plugin_path_throws`; - jest.doMock( - pluginPath, - () => { - throw new Error('initialization failure'); - }, - {virtual: true}, - ); + const pluginPath = `${__dirname}/__fixtures__/watch_plugin_throws`; - expect.assertions(1); - try { - await watch( + await expect( + watch( { ...globalConfig, rootDir: __dirname, @@ -599,12 +590,8 @@ describe('Watch mode flows', () => { pipe, hasteMapInstances, stdin, - ); - } catch (err) { - expect( - err.message.split(path.resolve(pluginPath)).join('PATH_REPLACED'), - ).toMatchSnapshot(); - } + ), + ).rejects.toMatchSnapshot(); }); it.each` diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 5a4c9a891334..428c8d7f9fa8 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import path from 'path'; import ansiEscapes from 'ansi-escapes'; import chalk from 'chalk'; import exit from 'exit'; @@ -179,16 +180,17 @@ export default function watch( stdin, stdout: outputStream, }); - } catch (err) { - return Promise.reject( - new Error( - `Failed to initialize watch plugin '${ - pluginWithConfig.path - }':\n\n${formatExecError(err, contexts[0].config, { - noStackTrace: false, - })}`, - ), + } catch (error) { + const errorWithContext = new Error( + `Failed to initialize watch plugin '${path.relative( + process.cwd(), + pluginWithConfig.path, + )}':\n\n${formatExecError(error, contexts[0].config, { + noStackTrace: false, + })}`, ); + delete errorWithContext.stack; + return Promise.reject(errorWithContext); } checkForConflicts(watchPluginKeys, plugin, globalConfig); From 0c169ab2878ef4e13768973bf2732a748169f794 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Mon, 6 May 2019 20:57:11 +0200 Subject: [PATCH 5/7] review and CI --- .../src/__tests__/__fixtures__/watch_plugin_throws.js | 2 ++ .../src/__tests__/__snapshots__/watch.test.js.snap | 4 ++-- packages/jest-core/src/watch.ts | 7 +++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js b/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js index 2238a551d2d9..076596c2837d 100644 --- a/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js +++ b/packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws.js @@ -1 +1,3 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + throw new Error('initialization error'); diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index 1ca0bd98bb58..be0c72787eaa 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -51,13 +51,13 @@ Watch Usage `; exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` -[Error: Failed to initialize watch plugin 'packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws': +[Error: Failed to initialize watch plugin "packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws": ● Test suite failed to run initialization error - at Object. (__fixtures__/watch_plugin_throws.js:1:7) + at Object. (__fixtures__/watch_plugin_throws.js:3:7) ] `; diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 428c8d7f9fa8..7033e59659db 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -182,10 +182,9 @@ export default function watch( }); } catch (error) { const errorWithContext = new Error( - `Failed to initialize watch plugin '${path.relative( - process.cwd(), - pluginWithConfig.path, - )}':\n\n${formatExecError(error, contexts[0].config, { + `Failed to initialize watch plugin "${chalk.bold( + path.posix.relative(process.cwd(), pluginWithConfig.path), + )}":\n\n${formatExecError(error, contexts[0].config, { noStackTrace: false, })}`, ); From 450eb11081bc554e14aa9ae19a180800fcadf24e Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Tue, 7 May 2019 00:15:32 +0200 Subject: [PATCH 6/7] CI --- .../src/__tests__/__snapshots__/watch.test.js.snap | 4 ++-- packages/jest-core/src/__tests__/watch.test.js | 11 +++++++---- packages/jest-core/src/watch.ts | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index be0c72787eaa..1a1382cec3f6 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -51,14 +51,14 @@ Watch Usage `; exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` -[Error: Failed to initialize watch plugin "packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws": +"Error: Failed to initialize watch plugin \\"packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws\\": ● Test suite failed to run initialization error at Object. (__fixtures__/watch_plugin_throws.js:3:7) -] +" `; exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = ` diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index 358446807c64..44742fcf76a1 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -579,8 +579,9 @@ describe('Watch mode flows', () => { it('makes watch plugin initialization errors look nice', async () => { const pluginPath = `${__dirname}/__fixtures__/watch_plugin_throws`; - await expect( - watch( + expect.assertions(1); + try { + await watch( { ...globalConfig, rootDir: __dirname, @@ -590,8 +591,10 @@ describe('Watch mode flows', () => { pipe, hasteMapInstances, stdin, - ), - ).rejects.toMatchSnapshot(); + ); + } catch (error) { + expect(error.toString().replace(/\\/, '/')).toMatchSnapshot(); + } }); it.each` diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 7033e59659db..57ed39a36b0c 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -183,7 +183,7 @@ export default function watch( } catch (error) { const errorWithContext = new Error( `Failed to initialize watch plugin "${chalk.bold( - path.posix.relative(process.cwd(), pluginWithConfig.path), + path.relative(process.cwd(), pluginWithConfig.path), )}":\n\n${formatExecError(error, contexts[0].config, { noStackTrace: false, })}`, From ce869dfb5a74ca76a9e261e8b7f75ed8ddca80f6 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Tue, 7 May 2019 09:28:10 +0200 Subject: [PATCH 7/7] try slash to fix Windows CI --- packages/jest-core/package.json | 2 ++ .../src/__tests__/__snapshots__/watch.test.js.snap | 4 ++-- packages/jest-core/src/__tests__/watch.test.js | 11 ++++------- packages/jest-core/src/watch.ts | 3 ++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/jest-core/package.json b/packages/jest-core/package.json index 8f7ca0c135f2..9f980af3c53d 100644 --- a/packages/jest-core/package.json +++ b/packages/jest-core/package.json @@ -31,6 +31,7 @@ "pirates": "^4.0.1", "realpath-native": "^1.1.0", "rimraf": "^2.5.4", + "slash": "^2.0.0", "strip-ansi": "^5.0.0" }, "devDependencies": { @@ -41,6 +42,7 @@ "@types/micromatch": "^3.1.0", "@types/p-each-series": "^1.0.0", "@types/rimraf": "^2.0.2", + "@types/slash": "^2.0.0", "@types/strip-ansi": "^3.0.0" }, "engines": { diff --git a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap index 1a1382cec3f6..be0c72787eaa 100644 --- a/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap +++ b/packages/jest-core/src/__tests__/__snapshots__/watch.test.js.snap @@ -51,14 +51,14 @@ Watch Usage `; exports[`Watch mode flows makes watch plugin initialization errors look nice 1`] = ` -"Error: Failed to initialize watch plugin \\"packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws\\": +[Error: Failed to initialize watch plugin "packages/jest-core/src/__tests__/__fixtures__/watch_plugin_throws": ● Test suite failed to run initialization error at Object. (__fixtures__/watch_plugin_throws.js:3:7) -" +] `; exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = ` diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index 44742fcf76a1..358446807c64 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -579,9 +579,8 @@ describe('Watch mode flows', () => { it('makes watch plugin initialization errors look nice', async () => { const pluginPath = `${__dirname}/__fixtures__/watch_plugin_throws`; - expect.assertions(1); - try { - await watch( + await expect( + watch( { ...globalConfig, rootDir: __dirname, @@ -591,10 +590,8 @@ describe('Watch mode flows', () => { pipe, hasteMapInstances, stdin, - ); - } catch (error) { - expect(error.toString().replace(/\\/, '/')).toMatchSnapshot(); - } + ), + ).rejects.toMatchSnapshot(); }); it.each` diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 57ed39a36b0c..5b97d1623709 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -9,6 +9,7 @@ import path from 'path'; import ansiEscapes from 'ansi-escapes'; import chalk from 'chalk'; import exit from 'exit'; +import slash from 'slash'; import HasteMap, {HasteChangeEvent} from 'jest-haste-map'; import {formatExecError} from 'jest-message-util'; import {isInteractive, preRunMessage, specialChars} from 'jest-util'; @@ -183,7 +184,7 @@ export default function watch( } catch (error) { const errorWithContext = new Error( `Failed to initialize watch plugin "${chalk.bold( - path.relative(process.cwd(), pluginWithConfig.path), + slash(path.relative(process.cwd(), pluginWithConfig.path)), )}":\n\n${formatExecError(error, contexts[0].config, { noStackTrace: false, })}`,