From 486f1fde257a19d3f227bad8fe123f1985998004 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 12:33:16 +0200 Subject: [PATCH 01/13] chore: add babel plugin to make sure Jest is unaffected by fake Promise implementations --- CHANGELOG.md | 1 + .../jest_adapter_init.js | 3 +- packages/jest-circus/src/run.js | 3 -- packages/jest-circus/src/utils.js | 6 ---- packages/jest-jasmine2/src/jasmine/Env.js | 5 ---- packages/jest-jasmine2/src/p_cancelable.js | 4 --- packages/jest-jasmine2/src/p_timeout.js | 4 --- packages/jest-jasmine2/src/queue_runner.js | 5 ---- packages/jest-jasmine2/src/reporter.js | 4 --- packages/jest-jasmine2/src/tree_processor.js | 5 ---- scripts/babel-plugin-jest-native-promise.js | 30 +++++++++++++++++++ scripts/build.js | 1 + 12 files changed, 33 insertions(+), 38 deletions(-) create mode 100644 scripts/babel-plugin-jest-native-promise.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ebdec78cb0c..a4d80727ab89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ - `[jest-test-typescript-parser]` Remove from the repository ([#7232](https://github.com/facebook/jest/pull/7232)) - `[tests]` Free tests from the dependency on value of FORCE_COLOR ([#6585](https://github.com/facebook/jest/pull/6585/files)) - `[jest-diff]` Standardize filenames ([#7238](https://github.com/facebook/jest/pull/7238)) +- `[*]` Add babel plugin to make sure Jest is unaffected by fake Promise implementations ### Performance diff --git a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js index 34108cb12307..49d5727a3902 100644 --- a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js +++ b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js @@ -19,12 +19,11 @@ import { buildSnapshotResolver, } from 'jest-snapshot'; import {addEventHandler, dispatch, ROOT_DESCRIBE_BLOCK_NAME} from '../state'; -import {getTestID, getOriginalPromise} from '../utils'; +import {getTestID} from '../utils'; import run from '../run'; // eslint-disable-next-line import/default import globals from '../index'; -const Promise = getOriginalPromise(); export const initialize = ({ config, getPrettier, diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index 37fcfc8d1616..507dfc441193 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -23,11 +23,8 @@ import { getTestID, invariant, makeRunResult, - getOriginalPromise, } from './utils'; -const Promise = getOriginalPromise(); - const run = async (): Promise => { const {rootDescribeBlock} = getState(); dispatch({name: 'run_start'}); diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index 2f0a44af3c37..96da54744ecf 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -32,12 +32,6 @@ import prettyFormat from 'pretty-format'; import {getState} from './state'; -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. Async functions return it implicitly. -// eslint-disable-next-line no-unused-vars -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; -export const getOriginalPromise = () => Promise; - const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); export const makeDescribe = ( diff --git a/packages/jest-jasmine2/src/jasmine/Env.js b/packages/jest-jasmine2/src/jasmine/Env.js index 0e57d1f1968b..21d27d753c23 100644 --- a/packages/jest-jasmine2/src/jasmine/Env.js +++ b/packages/jest-jasmine2/src/jasmine/Env.js @@ -37,11 +37,6 @@ import checkIsError from '../is_error'; import assertionErrorMessage from '../assert_support'; import {ErrorWithStack} from 'jest-util'; -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. Async functions return it implicitly. -// eslint-disable-next-line no-unused-vars -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; - export default function(j$) { function Env(options) { options = options || {}; diff --git a/packages/jest-jasmine2/src/p_cancelable.js b/packages/jest-jasmine2/src/p_cancelable.js index 1b54f624c6d7..4af085802444 100644 --- a/packages/jest-jasmine2/src/p_cancelable.js +++ b/packages/jest-jasmine2/src/p_cancelable.js @@ -2,10 +2,6 @@ 'use strict'; -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; - class CancelError extends Error { constructor() { super('Promise was canceled'); diff --git a/packages/jest-jasmine2/src/p_timeout.js b/packages/jest-jasmine2/src/p_timeout.js index 99c217ea5ce7..f255f3440a5a 100644 --- a/packages/jest-jasmine2/src/p_timeout.js +++ b/packages/jest-jasmine2/src/p_timeout.js @@ -7,10 +7,6 @@ * @flow */ -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; - // A specialized version of `p-timeout` that does not touch globals. // It does not throw on timeout. export default function pTimeout( diff --git a/packages/jest-jasmine2/src/queue_runner.js b/packages/jest-jasmine2/src/queue_runner.js index d72ec1bfabbd..4a8e80ab4141 100644 --- a/packages/jest-jasmine2/src/queue_runner.js +++ b/packages/jest-jasmine2/src/queue_runner.js @@ -7,11 +7,6 @@ * @flow */ -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. -const Promise: Class = - global[Symbol.for('jest-native-promise')] || global.Promise; - import PCancelable from './p_cancelable'; import pTimeout from './p_timeout'; diff --git a/packages/jest-jasmine2/src/reporter.js b/packages/jest-jasmine2/src/reporter.js index 2a867736f29a..0b482c44fca5 100644 --- a/packages/jest-jasmine2/src/reporter.js +++ b/packages/jest-jasmine2/src/reporter.js @@ -16,10 +16,6 @@ import type { TestResult, } from 'types/TestResult'; -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; - import {formatResultsErrors} from 'jest-message-util'; type Suite = { diff --git a/packages/jest-jasmine2/src/tree_processor.js b/packages/jest-jasmine2/src/tree_processor.js index 1245ee7a4494..6cf093c1787b 100644 --- a/packages/jest-jasmine2/src/tree_processor.js +++ b/packages/jest-jasmine2/src/tree_processor.js @@ -26,11 +26,6 @@ type TreeNode = { children?: Array, }; -// Try getting the real promise object from the context, if available. Someone -// could have overridden it in a test. Async functions return it implicitly. -// eslint-disable-next-line no-unused-vars -const Promise = global[Symbol.for('jest-native-promise')] || global.Promise; - export default function treeProcessor(options: Options) { const { nodeComplete, diff --git a/scripts/babel-plugin-jest-native-promise.js b/scripts/babel-plugin-jest-native-promise.js new file mode 100644 index 000000000000..c694cfbc1a63 --- /dev/null +++ b/scripts/babel-plugin-jest-native-promise.js @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +// This plugin exists to make sure that we use a `Promise` that has not been messed with by user code. +// Might consider extending this to other globals as well in the future + +const jestPromise = + "(global[Symbol.for('jest-native-promise')] || global.Promise)"; + +module.exports = () => ({ + name: 'jest-native-promise', + visitor: { + MemberExpression(path) { + if (path.node.object.name === 'Promise') { + path.node.object.name = jestPromise; + } + }, + NewExpression(path) { + if (path.node.callee.name === 'Promise') { + path.node.callee.name = jestPromise; + } + }, + }, +}); diff --git a/scripts/build.js b/scripts/build.js index ebaf99bca2ba..d56db4414f3c 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -166,6 +166,7 @@ function buildFile(file, silent) { }, ]); } + options.plugins.push(require.resolve('./babel-plugin-jest-native-promise')); const transformed = babel.transformFileSync(file, options).code; const prettyCode = prettier.format(transformed, prettierConfig); From 7123bc9f782fbe28c1ab0fbf9a6500dec17d2b7f Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 12:40:37 +0200 Subject: [PATCH 02/13] link to PR --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4d80727ab89..5dcbe823063a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,7 +80,7 @@ - `[jest-test-typescript-parser]` Remove from the repository ([#7232](https://github.com/facebook/jest/pull/7232)) - `[tests]` Free tests from the dependency on value of FORCE_COLOR ([#6585](https://github.com/facebook/jest/pull/6585/files)) - `[jest-diff]` Standardize filenames ([#7238](https://github.com/facebook/jest/pull/7238)) -- `[*]` Add babel plugin to make sure Jest is unaffected by fake Promise implementations +- `[*]` Add babel plugin to make sure Jest is unaffected by fake Promise implementations ([#7225](https://github.com/facebook/jest/pull/7225)) ### Performance From 66fbc9baec29613dc7c70750d10021f9d6b35271 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 12:47:14 +0200 Subject: [PATCH 03/13] flow --- packages/jest-jasmine2/src/queue_runner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jest-jasmine2/src/queue_runner.js b/packages/jest-jasmine2/src/queue_runner.js index 4a8e80ab4141..280a1ff73edd 100644 --- a/packages/jest-jasmine2/src/queue_runner.js +++ b/packages/jest-jasmine2/src/queue_runner.js @@ -22,6 +22,7 @@ type Options = { type QueueableFn = { fn: (next: () => void) => void, timeout?: () => number, + initError?: Error, }; export default function queueRunner(options: Options) { @@ -29,7 +30,7 @@ export default function queueRunner(options: Options) { onCancel(resolve); }); - const mapper = ({fn, timeout, initError = new Error()}) => { + const mapper = ({fn, timeout, initError = new Error()}: QueueableFn) => { let promise = new Promise(resolve => { const next = function(err) { if (err) { From 54faa8b7b4825b50e7edc80005c87e324d5a24a8 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 13:04:24 +0200 Subject: [PATCH 04/13] more flow --- .../jest_adapter_init.js | 74 ++++++++++--------- types/Circus.js | 1 + types/TestResult.js | 1 + 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js index 49d5727a3902..9ceed2811e66 100644 --- a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js +++ b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js @@ -7,9 +7,9 @@ * @flow */ -import type {TestResult, Status} from 'types/TestResult'; +import type {AssertionResult, TestResult, Status} from 'types/TestResult'; import type {GlobalConfig, Path, ProjectConfig} from 'types/Config'; -import type {Event, TestEntry} from 'types/Circus'; +import type {Event, RunResult, TestEntry} from 'types/Circus'; import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; @@ -122,46 +122,48 @@ export const runAndTransformResultsToJestFormat = async ({ globalConfig: GlobalConfig, testPath: string, }): Promise => { - const runResult = await run(); + const runResult: RunResult = await run(); let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; let numTodoTests = 0; - const assertionResults = runResult.testResults.map(testResult => { - let status: Status; - if (testResult.status === 'skip') { - status = 'pending'; - numPendingTests += 1; - } else if (testResult.status === 'todo') { - status = 'todo'; - numTodoTests += 1; - } else if (testResult.errors.length) { - status = 'failed'; - numFailingTests += 1; - } else { - status = 'passed'; - numPassingTests += 1; - } - - const ancestorTitles = testResult.testPath.filter( - name => name !== ROOT_DESCRIBE_BLOCK_NAME, - ); - const title = ancestorTitles.pop(); - - return { - ancestorTitles, - duration: testResult.duration, - failureMessages: testResult.errors, - fullName: ancestorTitles.concat(title).join(' '), - invocations: testResult.invocations, - location: testResult.location, - numPassingAsserts: 0, - status, - title: testResult.testPath[testResult.testPath.length - 1], - }; - }); + const assertionResults: Array = runResult.testResults.map( + testResult => { + let status: Status; + if (testResult.status === 'skip') { + status = 'pending'; + numPendingTests += 1; + } else if (testResult.status === 'todo') { + status = 'todo'; + numTodoTests += 1; + } else if (testResult.errors.length) { + status = 'failed'; + numFailingTests += 1; + } else { + status = 'passed'; + numPassingTests += 1; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== ROOT_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: ancestorTitles.concat(title).join(' '), + invocations: testResult.invocations, + location: testResult.location, + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; + }, + ); let failureMessage = formatResultsErrors( assertionResults, diff --git a/types/Circus.js b/types/Circus.js index 7a95671f9460..28f56b1c0fdd 100644 --- a/types/Circus.js +++ b/types/Circus.js @@ -153,6 +153,7 @@ export type TestStatus = 'skip' | 'done' | 'todo'; export type TestResult = {| duration: ?number, errors: Array, + invocations: number, status: TestStatus, location: ?{|column: number, line: number|}, testPath: Array, diff --git a/types/TestResult.js b/types/TestResult.js index 928dc0d280e8..7ef862e2308e 100644 --- a/types/TestResult.js +++ b/types/TestResult.js @@ -98,6 +98,7 @@ export type AssertionResult = {| duration?: ?Milliseconds, failureMessages: Array, fullName: string, + invocations?: number, location: ?Callsite, numPassingAsserts: number, status: Status, From 2a10e5a9f3b39ba88784c8268035e8ba0f75989e Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 13:26:24 +0200 Subject: [PATCH 05/13] only add plugin to modules injected into the user sandbox --- scripts/build.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/build.js b/scripts/build.js index d56db4414f3c..07af2abdf4b6 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -150,7 +150,13 @@ function buildFile(file, silent) { const options = Object.assign({}, transformOptions); options.plugins = options.plugins.slice(); - if (!INLINE_REQUIRE_BLACKLIST.test(file)) { + if (INLINE_REQUIRE_BLACKLIST.test(file)) { + // The modules in the blacklist are injected into the user's sandbox + // We need to guard `Promise` there. + options.plugins.push( + require.resolve('./babel-plugin-jest-native-promise') + ); + } else { // Remove normal plugin. options.plugins = options.plugins.filter( plugin => @@ -166,7 +172,6 @@ function buildFile(file, silent) { }, ]); } - options.plugins.push(require.resolve('./babel-plugin-jest-native-promise')); const transformed = babel.transformFileSync(file, options).code; const prettyCode = prettier.format(transformed, prettierConfig); From 1dbd666be9588cf2b3ac6b02e6c66b9868b4d0e2 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 13:35:08 +0200 Subject: [PATCH 06/13] blockname cannot be a function --- types/Circus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/Circus.js b/types/Circus.js index 28f56b1c0fdd..ae13529ed043 100644 --- a/types/Circus.js +++ b/types/Circus.js @@ -9,7 +9,7 @@ export type DoneFn = (reason?: string | Error) => void; export type BlockFn = () => void; -export type BlockName = string | Function; +export type BlockName = string; export type BlockMode = void | 'skip' | 'only' | 'todo'; export type TestMode = BlockMode; export type TestName = string; From ffc6d87a20a2fc10b572456e632bb74b017a188f Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 14:35:45 +0200 Subject: [PATCH 07/13] collect coverage from node 10 instead --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e3cadb0b6788..b879e457b890 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,7 +51,7 @@ jobs: - run: yarn --no-progress - save-cache: *save-cache - run: - command: yarn test-ci-partial + command: yarn test-ci - store_test_results: path: reports/junit @@ -79,7 +79,7 @@ jobs: - run: yarn --no-progress - save-cache: *save-cache - run: - command: yarn test-ci + command: yarn test-ci-partial - store_test_results: path: reports/junit From 9ea535448abf9d6326c114bc646831c017f7e5f8 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 14:53:04 +0200 Subject: [PATCH 08/13] use normal reporters --- jest.config.ci.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jest.config.ci.js b/jest.config.ci.js index c28f6d8db341..b340d974470c 100644 --- a/jest.config.ci.js +++ b/jest.config.ci.js @@ -2,9 +2,8 @@ // Object spread is just node 8 module.exports = Object.assign({}, require('./jest.config'), { - coverageReporters: ['json'], reporters: [ ['jest-junit', {output: 'reports/junit/js-test-results.xml'}], - ['jest-silent-reporter', {useDots: true}], + 'default', ], }); From 084795ecb8e34494a0159b5d6e7ff20bf24aed08 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 16:10:34 +0200 Subject: [PATCH 09/13] don't use Symbol for our promise --- packages/jest-util/src/install_common_globals.js | 7 ++++++- scripts/babel-plugin-jest-native-promise.js | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/jest-util/src/install_common_globals.js b/packages/jest-util/src/install_common_globals.js index 5eada9d75747..fa09eb0b85b6 100644 --- a/packages/jest-util/src/install_common_globals.js +++ b/packages/jest-util/src/install_common_globals.js @@ -19,7 +19,12 @@ export default function(globalObject: Global, globals: ConfigGlobals) { globalObject.process = createProcessObject(); // Keep a reference to "Promise", since "jasmine_light.js" needs it. - globalObject[globalObject.Symbol.for('jest-native-promise')] = Promise; + Object.defineProperty(globalObject, 'jest-promise-stay-away', { + configurable: false, + enumerable: false, + value: Promise, + writable: false, + }); // Forward some APIs. DTRACE.forEach(dtrace => { diff --git a/scripts/babel-plugin-jest-native-promise.js b/scripts/babel-plugin-jest-native-promise.js index c694cfbc1a63..475c6c3a2e4c 100644 --- a/scripts/babel-plugin-jest-native-promise.js +++ b/scripts/babel-plugin-jest-native-promise.js @@ -10,8 +10,7 @@ // This plugin exists to make sure that we use a `Promise` that has not been messed with by user code. // Might consider extending this to other globals as well in the future -const jestPromise = - "(global[Symbol.for('jest-native-promise')] || global.Promise)"; +const jestPromise = "(global['jest-promise-stay-away'] || global.Promise)"; module.exports = () => ({ name: 'jest-native-promise', From 451666e6ecb01b807d3d806ca50122311f817870 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 16:20:47 +0200 Subject: [PATCH 10/13] Revert "use normal reporters" This reverts commit 493f7ee7c2e1da135f3b3af432f8c2ed398f4825. --- jest.config.ci.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jest.config.ci.js b/jest.config.ci.js index b340d974470c..c28f6d8db341 100644 --- a/jest.config.ci.js +++ b/jest.config.ci.js @@ -2,8 +2,9 @@ // Object spread is just node 8 module.exports = Object.assign({}, require('./jest.config'), { + coverageReporters: ['json'], reporters: [ ['jest-junit', {output: 'reports/junit/js-test-results.xml'}], - 'default', + ['jest-silent-reporter', {useDots: true}], ], }); From 20efbc70edfc4052498601a0c548a1aa24edbd91 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 16:20:54 +0200 Subject: [PATCH 11/13] Revert "collect coverage from node 10 instead" This reverts commit 3ede7a0e45469427726a5b7fb1dfc9aa15b50f2e. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b879e457b890..e3cadb0b6788 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,7 +51,7 @@ jobs: - run: yarn --no-progress - save-cache: *save-cache - run: - command: yarn test-ci + command: yarn test-ci-partial - store_test_results: path: reports/junit @@ -79,7 +79,7 @@ jobs: - run: yarn --no-progress - save-cache: *save-cache - run: - command: yarn test-ci-partial + command: yarn test-ci - store_test_results: path: reports/junit From fdf9346a2d9636e420ecaf6e78ee173a91ae793f Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 19:10:50 +0200 Subject: [PATCH 12/13] Revert "don't use Symbol for our promise" This reverts commit 48da08737e0ebb2705365b9dbcc74282cc61220c. --- packages/jest-util/src/install_common_globals.js | 7 +------ scripts/babel-plugin-jest-native-promise.js | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/jest-util/src/install_common_globals.js b/packages/jest-util/src/install_common_globals.js index fa09eb0b85b6..5eada9d75747 100644 --- a/packages/jest-util/src/install_common_globals.js +++ b/packages/jest-util/src/install_common_globals.js @@ -19,12 +19,7 @@ export default function(globalObject: Global, globals: ConfigGlobals) { globalObject.process = createProcessObject(); // Keep a reference to "Promise", since "jasmine_light.js" needs it. - Object.defineProperty(globalObject, 'jest-promise-stay-away', { - configurable: false, - enumerable: false, - value: Promise, - writable: false, - }); + globalObject[globalObject.Symbol.for('jest-native-promise')] = Promise; // Forward some APIs. DTRACE.forEach(dtrace => { diff --git a/scripts/babel-plugin-jest-native-promise.js b/scripts/babel-plugin-jest-native-promise.js index 475c6c3a2e4c..c694cfbc1a63 100644 --- a/scripts/babel-plugin-jest-native-promise.js +++ b/scripts/babel-plugin-jest-native-promise.js @@ -10,7 +10,8 @@ // This plugin exists to make sure that we use a `Promise` that has not been messed with by user code. // Might consider extending this to other globals as well in the future -const jestPromise = "(global['jest-promise-stay-away'] || global.Promise)"; +const jestPromise = + "(global[Symbol.for('jest-native-promise')] || global.Promise)"; module.exports = () => ({ name: 'jest-native-promise', From 77b8e824a667227aa8d9e59e7bf66a0af71f2015 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 20 Oct 2018 19:16:31 +0200 Subject: [PATCH 13/13] PR feedback --- scripts/babel-plugin-jest-native-promise.js | 33 +++++++++++---------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/scripts/babel-plugin-jest-native-promise.js b/scripts/babel-plugin-jest-native-promise.js index c694cfbc1a63..b0fa9e57db85 100644 --- a/scripts/babel-plugin-jest-native-promise.js +++ b/scripts/babel-plugin-jest-native-promise.js @@ -10,21 +10,22 @@ // This plugin exists to make sure that we use a `Promise` that has not been messed with by user code. // Might consider extending this to other globals as well in the future -const jestPromise = - "(global[Symbol.for('jest-native-promise')] || global.Promise)"; +module.exports = ({template}) => { + const promiseDeclaration = template(` + var Promise = global[Symbol.for('jest-native-promise')] || global.Promise; + `); -module.exports = () => ({ - name: 'jest-native-promise', - visitor: { - MemberExpression(path) { - if (path.node.object.name === 'Promise') { - path.node.object.name = jestPromise; - } + return { + name: 'jest-native-promise', + visitor: { + ReferencedIdentifier(path, state) { + if (path.node.name === 'Promise' && !state.injectedPromise) { + state.injectedPromise = true; + path + .findParent(p => p.isProgram()) + .unshiftContainer('body', promiseDeclaration()); + } + }, }, - NewExpression(path) { - if (path.node.callee.name === 'Promise') { - path.node.callee.name = jestPromise; - } - }, - }, -}); + }; +};