From e21ae1188dea8bf78504054dde6074f507beb01c Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 24 Oct 2018 22:28:59 +0200 Subject: [PATCH] fix: display test duration even if time is mocked out (#7264) --- CHANGELOG.md | 1 + e2e/__tests__/override-globals.test.js | 11 +++++++++ e2e/override-globals/package.json | 5 +++- e2e/override-globals/setup.js | 2 ++ packages/jest-circus/src/utils.js | 2 +- .../jest-util/src/install_common_globals.js | 8 +++++-- ...js => babel-plugin-jest-native-globals.js} | 23 ++++++++++++++++--- scripts/build.js | 4 ++-- 8 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 e2e/override-globals/setup.js rename scripts/{babel-plugin-jest-native-promise.js => babel-plugin-jest-native-globals.js} (52%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dcbe823063a..d53348f215f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - `[jest-changed-files]` Return correctly the changed files when using `lastCommit=true` on Mercurial repositories ([#7228](https://github.com/facebook/jest/pull/7228)) - `[babel-jest]` Cache includes babel environment variables ([#7239](https://github.com/facebook/jest/pull/7239)) - `[jest-config]` Use strings instead of `RegExp` instances in normalized configuration ([#7251](https://github.com/facebook/jest/pull/7251)) +- `[jest-circus]` Make sure to display real duration even if time is mocked ([#7264](https://github.com/facebook/jest/pull/7264)) ### Chore & Maintenance diff --git a/e2e/__tests__/override-globals.test.js b/e2e/__tests__/override-globals.test.js index a8ad8ac7c252..489f43e76987 100644 --- a/e2e/__tests__/override-globals.test.js +++ b/e2e/__tests__/override-globals.test.js @@ -15,3 +15,14 @@ test('overriding native promise does not freeze Jest', () => { const run = runJest('override-globals'); expect(run.stderr).toMatch(/PASS __tests__(\/|\\)index.js/); }); + +test('has a duration even if time is faked', () => { + const regex = /works well \((\d+)ms\)/; + const {stderr} = runJest('override-globals', ['--verbose']); + + expect(stderr).toMatch(regex); + + const [, duration] = stderr.match(regex); + + expect(Number(duration)).toBeGreaterThan(0); +}); diff --git a/e2e/override-globals/package.json b/e2e/override-globals/package.json index 148788b25446..b4a435775e2b 100644 --- a/e2e/override-globals/package.json +++ b/e2e/override-globals/package.json @@ -1,5 +1,8 @@ { "jest": { - "testEnvironment": "node" + "testEnvironment": "node", + "setupFiles": [ + "/setup.js" + ] } } diff --git a/e2e/override-globals/setup.js b/e2e/override-globals/setup.js new file mode 100644 index 000000000000..0fb3e1ade0c8 --- /dev/null +++ b/e2e/override-globals/setup.js @@ -0,0 +1,2 @@ +Date.now = () => 0; +process.hrtime = () => [0, 5000]; diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index 96da54744ecf..328566bbcfb5 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -240,7 +240,7 @@ export const callAsyncCircusFn = ( export const getTestDuration = (test: TestEntry): ?number => { const {startedAt} = test; - return startedAt ? Date.now() - startedAt : null; + return typeof startedAt === 'number' ? Date.now() - startedAt : null; }; export const makeRunResult = ( diff --git a/packages/jest-util/src/install_common_globals.js b/packages/jest-util/src/install_common_globals.js index 5eada9d75747..d87e16a28861 100644 --- a/packages/jest-util/src/install_common_globals.js +++ b/packages/jest-util/src/install_common_globals.js @@ -18,8 +18,12 @@ const DTRACE = Object.keys(global).filter(key => key.startsWith('DTRACE')); 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; + const symbol = globalObject.Symbol; + // Keep a reference to some globals that Jest needs + globalObject[symbol.for('jest-native-promise')] = Promise; + globalObject[symbol.for('jest-native-now')] = globalObject.Date.now.bind( + globalObject.Date, + ); // Forward some APIs. DTRACE.forEach(dtrace => { diff --git a/scripts/babel-plugin-jest-native-promise.js b/scripts/babel-plugin-jest-native-globals.js similarity index 52% rename from scripts/babel-plugin-jest-native-promise.js rename to scripts/babel-plugin-jest-native-globals.js index b0fa9e57db85..a0e01e20b942 100644 --- a/scripts/babel-plugin-jest-native-promise.js +++ b/scripts/babel-plugin-jest-native-globals.js @@ -14,17 +14,34 @@ module.exports = ({template}) => { const promiseDeclaration = template(` var Promise = global[Symbol.for('jest-native-promise')] || global.Promise; `); + const nowDeclaration = template(` + var jestNow = global[Symbol.for('jest-native-now')] || global.Date.now; + `); return { - name: 'jest-native-promise', + name: 'jest-native-globals', visitor: { ReferencedIdentifier(path, state) { - if (path.node.name === 'Promise' && !state.injectedPromise) { - state.injectedPromise = true; + if (path.node.name === 'Promise' && !state.jestInjectedPromise) { + state.jestInjectedPromise = true; path .findParent(p => p.isProgram()) .unshiftContainer('body', promiseDeclaration()); } + if ( + path.node.name === 'Date' && + path.parent.property && + path.parent.property.name === 'now' + ) { + if (!state.jestInjectedNow) { + state.jestInjectedNow = true; + path + .findParent(p => p.isProgram()) + .unshiftContainer('body', nowDeclaration()); + } + + path.parentPath.replaceWithSourceString('jestNow'); + } }, }, }; diff --git a/scripts/build.js b/scripts/build.js index 07af2abdf4b6..5ec139a7b9cd 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -152,9 +152,9 @@ function buildFile(file, silent) { if (INLINE_REQUIRE_BLACKLIST.test(file)) { // The modules in the blacklist are injected into the user's sandbox - // We need to guard `Promise` there. + // We need to guard some globals there. options.plugins.push( - require.resolve('./babel-plugin-jest-native-promise') + require.resolve('./babel-plugin-jest-native-globals') ); } else { // Remove normal plugin.