From 1bd8311391ec9e2ef3b45e01d10ba45148d2b06e Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Sun, 17 Mar 2019 21:06:02 -0700 Subject: [PATCH 01/10] Filter API pre-filter setup hook. --- e2e/__tests__/filter.test.ts | 7 +++++++ e2e/filter/my-setup-filter.js | 19 +++++++++++++++++++ packages/jest-core/src/cli/index.ts | 9 +++++++++ 3 files changed, 35 insertions(+) create mode 100644 e2e/filter/my-setup-filter.js diff --git a/e2e/__tests__/filter.test.ts b/e2e/__tests__/filter.test.ts index 550330fd507f..4ab9377f577a 100644 --- a/e2e/__tests__/filter.test.ts +++ b/e2e/__tests__/filter.test.ts @@ -43,4 +43,11 @@ describe('Dynamic test filtering', () => { expect(result.stderr).toContain('did not return a valid test list'); expect(result.stderr).toContain('my-clowny-filter'); }); + + it('will call setup on filter before filtering', () => { + const result = runJest('filter', ['--filter=/my-setup-filter.js']); + + expect(result.status).toBe(0); + expect(result.stderr).toContain('1 total'); + }); }); diff --git a/e2e/filter/my-setup-filter.js b/e2e/filter/my-setup-filter.js new file mode 100644 index 000000000000..70b4f8a06f11 --- /dev/null +++ b/e2e/filter/my-setup-filter.js @@ -0,0 +1,19 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +'use strict'; + +const setupData = { + filterText: 'this will return no tests', +}; + +module.exports = function(tests) { + return { + filtered: tests + .filter(t => t.indexOf(setupData.filterText) !== -1) + .map(test => ({test})), + }; +}; + +module.exports.setup = function() { + setupData.filterText = 'foo'; +}; diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index a1dce1db10b9..54e2b4941b8a 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -145,6 +145,15 @@ const _run = async ( // as soon as possible, so by the time we need the result it's already there. const changedFilesPromise = getChangedFilesPromise(globalConfig, configs); + // Filter may need to do an HTTP call or something similar to setup. + // We will not wait on an async response from this before using the filter. + if (globalConfig.filter && !globalConfig.skipFilter) { + const filter = require(globalConfig.filter); + if (filter.setup) { + filter.setup(); + } + } + const {contexts, hasteMapInstances} = await buildContextsAndHasteMaps( configs, globalConfig, From 0dfb5c5b2820cb91232ec7c5d64eac2e885d4a39 Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Mon, 18 Mar 2019 01:14:15 -0700 Subject: [PATCH 02/10] Ensure filter API setup Promise resolves before filtering. --- e2e/filter/my-setup-filter.js | 5 ++++- packages/jest-core/src/SearchSource.ts | 4 ++++ packages/jest-core/src/cli/index.ts | 8 +++++++- packages/jest-core/src/runJest.ts | 10 +++++++++- packages/jest-core/src/watch.ts | 2 ++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/e2e/filter/my-setup-filter.js b/e2e/filter/my-setup-filter.js index 70b4f8a06f11..a15eeec45dc1 100644 --- a/e2e/filter/my-setup-filter.js +++ b/e2e/filter/my-setup-filter.js @@ -14,6 +14,9 @@ module.exports = function(tests) { }; }; -module.exports.setup = function() { +module.exports.setup = async function() { + await new Promise(resolve => { + setTimeout(() => resolve(), 1000); + }); setupData.filterText = 'foo'; }; diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index ee28ca92bc8b..46d3c328e877 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -290,6 +290,7 @@ export default class SearchSource { async getTestPaths( globalConfig: Config.GlobalConfig, changedFiles: ChangedFiles | undefined, + filterSetupPromise?: Promise, ): Promise { const searchResult = this._getTestPaths(globalConfig, changedFiles); @@ -299,6 +300,9 @@ export default class SearchSource { const tests = searchResult.tests; const filter = require(filterPath); + if (filterSetupPromise) { + await filterSetupPromise; + } const filterResult: {filtered: Array} = await filter( tests.map(test => test.path), ); diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 54e2b4941b8a..2f76c23ee916 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -147,10 +147,11 @@ const _run = async ( // Filter may need to do an HTTP call or something similar to setup. // We will not wait on an async response from this before using the filter. + let filterSetupPromise: Promise | undefined; if (globalConfig.filter && !globalConfig.skipFilter) { const filter = require(globalConfig.filter); if (filter.setup) { - filter.setup(); + filterSetupPromise = filter.setup(); } } @@ -168,6 +169,7 @@ const _run = async ( globalConfig, outputStream, hasteMapInstances, + filterSetupPromise, ) : await runWithoutWatch( globalConfig, @@ -175,6 +177,7 @@ const _run = async ( outputStream, onComplete, changedFilesPromise, + filterSetupPromise, ); }; @@ -185,6 +188,7 @@ const runWatch = async ( globalConfig: Config.GlobalConfig, outputStream: NodeJS.WriteStream, hasteMapInstances: Array, + filterSetupPromise?: Promise, ) => { if (hasDeprecationWarnings) { try { @@ -204,6 +208,7 @@ const runWithoutWatch = async ( outputStream: NodeJS.WritableStream, onComplete: OnCompleteCallback, changedFilesPromise?: ChangedFilesPromise, + filterSetupPromise?: Promise, ) => { const startRun = async (): Promise => { if (!globalConfig.listTests) { @@ -218,6 +223,7 @@ const runWithoutWatch = async ( outputStream, startRun, testWatcher: new TestWatcher({isWatchMode: false}), + filterSetupPromise, }); }; return startRun(); diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 1e91cb16ec83..77c9f11f2194 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -37,9 +37,14 @@ const getTestPaths = async ( outputStream: NodeJS.WritableStream, changedFiles: ChangedFiles | undefined, jestHooks: JestHookEmitter, + filterSetupPromise?: Promise, ) => { const source = new SearchSource(context); - const data = await source.getTestPaths(globalConfig, changedFiles); + const data = await source.getTestPaths( + globalConfig, + changedFiles, + filterSetupPromise, + ); if (!data.tests.length && globalConfig.onlyChanged && data.noSCM) { new CustomConsole(outputStream, outputStream).log( @@ -129,6 +134,7 @@ export default (async function runJest({ changedFilesPromise, onComplete, failedTestsCache, + filterSetupPromise, }: { globalConfig: Config.GlobalConfig; contexts: Array; @@ -139,6 +145,7 @@ export default (async function runJest({ changedFilesPromise?: ChangedFilesPromise; onComplete: (testResults: AggregatedResult) => void; failedTestsCache?: FailedTestsCache; + filterSetupPromise?: Promise; }) { const sequencer = new TestSequencer(); let allTests: Array = []; @@ -168,6 +175,7 @@ export default (async function runJest({ outputStream, changedFilesPromise && (await changedFilesPromise), jestHooks, + filterSetupPromise, ); allTests = allTests.concat(matches.tests); diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index b372d33fc04d..769b283b0576 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -83,6 +83,7 @@ export default function watch( hasteMapInstances: Array, stdin: NodeJS.ReadStream = process.stdin, hooks: JestHook = new JestHook(), + filterSetupPromise?: Promise, ): Promise { // `globalConfig` will be constantly updated and reassigned as a result of // watch mode interactions. @@ -293,6 +294,7 @@ export default function watch( outputStream, startRun, testWatcher, + filterSetupPromise, }).catch(error => // Errors thrown inside `runJest`, e.g. by resolvers, are caught here for // continuous watch mode execution. We need to reprint them to the From 1464230e0f688ce35041a5a85af9844c8d5f0b6a Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Mon, 18 Mar 2019 08:57:54 -0700 Subject: [PATCH 03/10] Pass through wrapped filter to avoid including it twice. --- packages/jest-core/src/SearchSource.ts | 18 +++------- packages/jest-core/src/cli/index.ts | 46 ++++++++++++++++++++------ packages/jest-core/src/runJest.ts | 16 ++++----- packages/jest-core/src/types.ts | 11 ++++++ packages/jest-core/src/watch.ts | 5 +-- 5 files changed, 59 insertions(+), 37 deletions(-) diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 46d3c328e877..99f03b29781b 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -21,6 +21,7 @@ import { TestPathCases, TestPathCasesWithPathPattern, TestPathCaseWithPathPatternStats, + Filter, } from './types'; export type SearchResult = { @@ -41,11 +42,6 @@ export type TestSelectionConfig = { watch?: boolean; }; -type FilterResult = { - test: string; - message: string; -}; - const globsToMatcher = (globs?: Array | null) => { if (globs == null || globs.length === 0) { return () => true; @@ -290,22 +286,16 @@ export default class SearchSource { async getTestPaths( globalConfig: Config.GlobalConfig, changedFiles: ChangedFiles | undefined, - filterSetupPromise?: Promise, + filter?: Filter, ): Promise { const searchResult = this._getTestPaths(globalConfig, changedFiles); const filterPath = globalConfig.filter; - if (filterPath && !globalConfig.skipFilter) { + if (filter) { const tests = searchResult.tests; - const filter = require(filterPath); - if (filterSetupPromise) { - await filterSetupPromise; - } - const filterResult: {filtered: Array} = await filter( - tests.map(test => test.path), - ); + const filterResult = await filter(tests.map(test => test.path)); if (!Array.isArray(filterResult.filtered)) { throw new Error( diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 2f76c23ee916..743ce8bd5103 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -16,6 +16,7 @@ import HasteMap from 'jest-haste-map'; import chalk from 'chalk'; import rimraf from 'rimraf'; import exit from 'exit'; +import {Filter} from '../types'; import createContext from '../lib/create_context'; import getChangedFilesPromise from '../getChangedFilesPromise'; import {formatHandleErrors} from '../collectHandles'; @@ -147,12 +148,19 @@ const _run = async ( // Filter may need to do an HTTP call or something similar to setup. // We will not wait on an async response from this before using the filter. - let filterSetupPromise: Promise | undefined; + let filter: Filter | undefined; if (globalConfig.filter && !globalConfig.skipFilter) { - const filter = require(globalConfig.filter); - if (filter.setup) { - filterSetupPromise = filter.setup(); + const rawFilter = require(globalConfig.filter); + let filterSetupPromise: Promise | undefined; + if (rawFilter.setup) { + filterSetupPromise = rawFilter.setup(); } + filter = async (testPaths: Array) => { + if (filterSetupPromise) { + await filterSetupPromise; + } + return rawFilter(testPaths); + }; } const {contexts, hasteMapInstances} = await buildContextsAndHasteMaps( @@ -169,7 +177,7 @@ const _run = async ( globalConfig, outputStream, hasteMapInstances, - filterSetupPromise, + filter, ) : await runWithoutWatch( globalConfig, @@ -177,7 +185,7 @@ const _run = async ( outputStream, onComplete, changedFilesPromise, - filterSetupPromise, + filter, ); }; @@ -188,18 +196,34 @@ const runWatch = async ( globalConfig: Config.GlobalConfig, outputStream: NodeJS.WriteStream, hasteMapInstances: Array, - filterSetupPromise?: Promise, + filter?: Filter, ) => { if (hasDeprecationWarnings) { try { await handleDeprecationWarnings(outputStream, process.stdin); - return watch(globalConfig, contexts, outputStream, hasteMapInstances); + return watch( + globalConfig, + contexts, + outputStream, + hasteMapInstances, + undefined, + undefined, + filter, + ); } catch (e) { exit(0); } } - return watch(globalConfig, contexts, outputStream, hasteMapInstances); + return watch( + globalConfig, + contexts, + outputStream, + hasteMapInstances, + undefined, + undefined, + filter, + ); }; const runWithoutWatch = async ( @@ -208,7 +232,7 @@ const runWithoutWatch = async ( outputStream: NodeJS.WritableStream, onComplete: OnCompleteCallback, changedFilesPromise?: ChangedFilesPromise, - filterSetupPromise?: Promise, + filter?: Filter, ) => { const startRun = async (): Promise => { if (!globalConfig.listTests) { @@ -223,7 +247,7 @@ const runWithoutWatch = async ( outputStream, startRun, testWatcher: new TestWatcher({isWatchMode: false}), - filterSetupPromise, + filter, }); }; return startRun(); diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 77c9f11f2194..fad2435d8ee0 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -29,7 +29,7 @@ import TestSequencer from './TestSequencer'; import FailedTestsCache from './FailedTestsCache'; import collectNodeHandles from './collectHandles'; import TestWatcher from './TestWatcher'; -import {TestRunData} from './types'; +import {TestRunData, Filter} from './types'; const getTestPaths = async ( globalConfig: Config.GlobalConfig, @@ -37,14 +37,10 @@ const getTestPaths = async ( outputStream: NodeJS.WritableStream, changedFiles: ChangedFiles | undefined, jestHooks: JestHookEmitter, - filterSetupPromise?: Promise, + filter?: Filter, ) => { const source = new SearchSource(context); - const data = await source.getTestPaths( - globalConfig, - changedFiles, - filterSetupPromise, - ); + const data = await source.getTestPaths(globalConfig, changedFiles, filter); if (!data.tests.length && globalConfig.onlyChanged && data.noSCM) { new CustomConsole(outputStream, outputStream).log( @@ -134,7 +130,7 @@ export default (async function runJest({ changedFilesPromise, onComplete, failedTestsCache, - filterSetupPromise, + filter, }: { globalConfig: Config.GlobalConfig; contexts: Array; @@ -145,7 +141,7 @@ export default (async function runJest({ changedFilesPromise?: ChangedFilesPromise; onComplete: (testResults: AggregatedResult) => void; failedTestsCache?: FailedTestsCache; - filterSetupPromise?: Promise; + filter?: Filter; }) { const sequencer = new TestSequencer(); let allTests: Array = []; @@ -175,7 +171,7 @@ export default (async function runJest({ outputStream, changedFilesPromise && (await changedFilesPromise), jestHooks, - filterSetupPromise, + filter, ); allTests = allTests.concat(matches.tests); diff --git a/packages/jest-core/src/types.ts b/packages/jest-core/src/types.ts index 450f8095c3b9..9e57b7039c6c 100644 --- a/packages/jest-core/src/types.ts +++ b/packages/jest-core/src/types.ts @@ -38,3 +38,14 @@ export type TestPathCases = { export type TestPathCasesWithPathPattern = TestPathCases & { testPathPattern: (path: Config.Path) => boolean; }; + +export type FilterResult = { + test: string; + message: string; +}; + +export type Filter = ( + testPaths: Array, +) => Promise<{ + filtered: Array; +}>; diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 769b283b0576..b57b3bfdd013 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -39,6 +39,7 @@ import { filterInteractivePlugins, } from './lib/watch_plugins_helpers'; import activeFilters from './lib/active_filters_message'; +import {Filter} from './types'; type ReservedInfo = { forbiddenOverwriteMessage?: string; @@ -83,7 +84,7 @@ export default function watch( hasteMapInstances: Array, stdin: NodeJS.ReadStream = process.stdin, hooks: JestHook = new JestHook(), - filterSetupPromise?: Promise, + filter?: Filter, ): Promise { // `globalConfig` will be constantly updated and reassigned as a result of // watch mode interactions. @@ -294,7 +295,7 @@ export default function watch( outputStream, startRun, testWatcher, - filterSetupPromise, + filter, }).catch(error => // Errors thrown inside `runJest`, e.g. by resolvers, are caught here for // continuous watch mode execution. We need to reprint them to the From 784b77b59f14a21228adc0637696e269c5d3edb6 Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Mon, 18 Mar 2019 09:13:44 -0700 Subject: [PATCH 04/10] Resolve lint error. --- packages/jest-core/src/cli/index.ts | 2 +- packages/jest-core/src/watch.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 743ce8bd5103..4c0f91d5ca35 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -242,12 +242,12 @@ const runWithoutWatch = async ( changedFilesPromise, contexts, failedTestsCache: undefined, + filter, globalConfig, onComplete, outputStream, startRun, testWatcher: new TestWatcher({isWatchMode: false}), - filter, }); }; return startRun(); diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index b57b3bfdd013..2efe8e05b165 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -264,6 +264,7 @@ export default function watch( changedFilesPromise, contexts, failedTestsCache, + filter, globalConfig, jestHooks: hooks.getEmitter(), onComplete: results => { @@ -295,7 +296,6 @@ export default function watch( outputStream, startRun, testWatcher, - filter, }).catch(error => // Errors thrown inside `runJest`, e.g. by resolvers, are caught here for // continuous watch mode execution. We need to reprint them to the From f052897bf15d088164ebfadd87d4defd9482abdb Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Mon, 18 Mar 2019 10:39:33 -0700 Subject: [PATCH 05/10] Fix unit test for Node v6. --- e2e/filter/my-setup-filter.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/e2e/filter/my-setup-filter.js b/e2e/filter/my-setup-filter.js index a15eeec45dc1..62861b832114 100644 --- a/e2e/filter/my-setup-filter.js +++ b/e2e/filter/my-setup-filter.js @@ -14,9 +14,11 @@ module.exports = function(tests) { }; }; -module.exports.setup = async function() { - await new Promise(resolve => { - setTimeout(() => resolve(), 1000); +module.exports.setup = function() { + return new Promise(resolve => { + setTimeout(() => { + setupData.filterText = 'foo'; + resolve(); + }, 1000); }); - setupData.filterText = 'foo'; }; From 6d89fa3443072f06fa58ce810b50273b8f8289df Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Tue, 19 Mar 2019 08:39:12 -0700 Subject: [PATCH 06/10] Update changelog. --- CHANGELOG.md | 2 ++ packages/jest-core/src/cli/index.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 365621c5e1a0..ac21b7907d6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[*]` Filter API pre-filter setup hook ([#8142](https://github.com/facebook/jest/pull/8142)) + ### Fixes - `[pretty-format]` Print `BigInt` as a readable number instead of `{}` [#8138](https://github.com/facebook/jest/pull/8138) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 4c0f91d5ca35..45134fe60511 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -147,7 +147,7 @@ const _run = async ( const changedFilesPromise = getChangedFilesPromise(globalConfig, configs); // Filter may need to do an HTTP call or something similar to setup. - // We will not wait on an async response from this before using the filter. + // We will wait on an async response from this before using the filter. let filter: Filter | undefined; if (globalConfig.filter && !globalConfig.skipFilter) { const rawFilter = require(globalConfig.filter); From dd507f6d6d749337abef0e0f3247fb0b6fa2fb18 Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Tue, 19 Mar 2019 08:58:10 -0700 Subject: [PATCH 07/10] Add tests and improve behavior for errors in filter and setup filter. --- e2e/__tests__/filter.test.ts | 18 ++++++++++++++++++ e2e/filter/my-broken-filter.js | 7 +++++++ e2e/filter/my-broken-setup-filter.js | 17 +++++++++++++++++ packages/jest-core/src/cli/index.ts | 18 +++++++++++++++--- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 e2e/filter/my-broken-filter.js create mode 100644 e2e/filter/my-broken-setup-filter.js diff --git a/e2e/__tests__/filter.test.ts b/e2e/__tests__/filter.test.ts index 4ab9377f577a..32253ab77ed2 100644 --- a/e2e/__tests__/filter.test.ts +++ b/e2e/__tests__/filter.test.ts @@ -50,4 +50,22 @@ describe('Dynamic test filtering', () => { expect(result.status).toBe(0); expect(result.stderr).toContain('1 total'); }); + + it('will print error when filter throws', () => { + const result = runJest('filter', [ + '--filter=/my-broken-filter.js', + ]); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('Error: My broken filter error.'); + }); + + it('will return no results when setup hook throws', () => { + const result = runJest('filter', [ + '--filter=/my-broken-setup-filter.js', + ]); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('Error: My broken setup filter error.'); + }); }); diff --git a/e2e/filter/my-broken-filter.js b/e2e/filter/my-broken-filter.js new file mode 100644 index 000000000000..ad73cc9f1f33 --- /dev/null +++ b/e2e/filter/my-broken-filter.js @@ -0,0 +1,7 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +'use strict'; + +module.exports = async function(tests) { + throw new Error('My broken filter error.'); +}; diff --git a/e2e/filter/my-broken-setup-filter.js b/e2e/filter/my-broken-setup-filter.js new file mode 100644 index 000000000000..3a7651c0ccb9 --- /dev/null +++ b/e2e/filter/my-broken-setup-filter.js @@ -0,0 +1,17 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +'use strict'; + +module.exports = function(tests) { + return { + filtered: tests.filter(t => t.indexOf('foo') !== -1).map(test => ({test})), + }; +}; + +module.exports.setup = function() { + return new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error('My broken setup filter error.')); + }, 0); + }); +}; diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 45134fe60511..55c2bba14b4b 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -151,13 +151,25 @@ const _run = async ( let filter: Filter | undefined; if (globalConfig.filter && !globalConfig.skipFilter) { const rawFilter = require(globalConfig.filter); - let filterSetupPromise: Promise | undefined; + let filterSetupPromise: Promise | undefined; if (rawFilter.setup) { - filterSetupPromise = rawFilter.setup(); + // Wrap filter setup Promise to avoid "uncaught Promise" error. + // If an error is returned, we surface it in the return value. + filterSetupPromise = (async () => { + try { + await rawFilter.setup(); + } catch (err) { + return err; + } + })(); } filter = async (testPaths: Array) => { if (filterSetupPromise) { - await filterSetupPromise; + // Expect an undefined return value unless there was an error. + const err = await filterSetupPromise; + if (err) { + throw err; + } } return rawFilter(testPaths); }; From 8b34e39aedb1fb846a9897844895a8f85092f460 Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Tue, 19 Mar 2019 09:02:30 -0700 Subject: [PATCH 08/10] Resolve lint error. --- packages/jest-core/src/cli/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 55c2bba14b4b..ea14271226ee 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -161,6 +161,7 @@ const _run = async ( } catch (err) { return err; } + return undefined; })(); } filter = async (testPaths: Array) => { From fe25250fb9b8d8c3514cc68f3b1fd2831ccaf12e Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 19 Mar 2019 16:07:23 +0000 Subject: [PATCH 09/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13ca749859d6..2f45f4ed4845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features -- `[*]` Filter API pre-filter setup hook ([#8142](https://github.com/facebook/jest/pull/8142)) +- `[@jest/core]` Filter API pre-filter setup hook ([#8142](https://github.com/facebook/jest/pull/8142)) - `[jest-snapshot]` Improve report when matcher fails, part 14 ([#8132](https://github.com/facebook/jest/pull/8132)) - `[@jest/reporter]` Display todo and skip test descriptions when verbose is true ([#8038](https://github.com/facebook/jest/pull/8038)) From 4d392ce43e9b36014a3399f76b802f73628a8983 Mon Sep 17 00:00:00 2001 From: Scott Hovestadt Date: Tue, 19 Mar 2019 09:54:56 -0700 Subject: [PATCH 10/10] Fix broken filter test in Node 6. --- e2e/filter/my-broken-filter.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/filter/my-broken-filter.js b/e2e/filter/my-broken-filter.js index ad73cc9f1f33..a1faac8150a9 100644 --- a/e2e/filter/my-broken-filter.js +++ b/e2e/filter/my-broken-filter.js @@ -2,6 +2,8 @@ 'use strict'; -module.exports = async function(tests) { - throw new Error('My broken filter error.'); +module.exports = function(tests) { + return new Promise((resolve, reject) => { + reject(new Error('My broken filter error.')); + }); };