Skip to content

Commit

Permalink
feat: add fakeTimersLolex to the test environments (#8925)
Browse files Browse the repository at this point in the history
* feat: add fakeTimersLolex to the test environments

* link to PR
  • Loading branch information
SimenB committed Sep 8, 2019
1 parent 04efbeb commit 0935f7c
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 45 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,8 @@
- `[jest-diff]` [**BREAKING**] Export as ECMAScript module ([#8873](https://github.com/facebook/jest/pull/8873))
- `[jest-diff]` Add `includeChangeCounts` and rename `Indicator` options ([#8881](https://github.com/facebook/jest/pull/8881))
- `[jest-diff]` Add `changeColor` and `patchColor` options ([#8911](https://github.com/facebook/jest/pull/8911))
- `[jest-environment-jsdom]` Add `fakeTimersLolex` ([#8925](https://github.com/facebook/jest/pull/8925))
- `[jest-environment-node]` Add `fakeTimersLolex` ([#8925](https://github.com/facebook/jest/pull/8925))
- `[@jest/fake-timers]` Add Lolex as implementation of fake timers ([#8897](https://github.com/facebook/jest/pull/8897))
- `[jest-get-type]` Add `BigInt` support. ([#8382](https://github.com/facebook/jest/pull/8382))
- `[jest-matcher-utils]` Add `BigInt` support to `ensureNumbers` `ensureActualIsNumber`, `ensureExpectedIsNumber` ([#8382](https://github.com/facebook/jest/pull/8382))
Expand Down
2 changes: 1 addition & 1 deletion TestUtils.ts
Expand Up @@ -115,7 +115,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = {
testPathIgnorePatterns: [],
testRegex: ['\\.test\\.js$'],
testRunner: 'jest-jasmine2',
testURL: '',
testURL: 'http://localhost',
timers: 'real',
transform: [],
transformIgnorePatterns: [],
Expand Down
Expand Up @@ -56,7 +56,7 @@ exports[`prints the config object 1`] = `
"\\\\.test\\\\.js$"
],
"testRunner": "myRunner",
"testURL": "",
"testURL": "http://localhost",
"timers": "real",
"transform": [],
"transformIgnorePatterns": [],
Expand Down
Expand Up @@ -4,21 +4,27 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const JSDomEnvironment = jest.requireActual('../');
import JSDomEnvironment = require('../');
import {makeProjectConfig} from '../../../../TestUtils';

describe('JSDomEnvironment', () => {
it('should configure setTimeout/setInterval to use the browser api', () => {
const env1 = new JSDomEnvironment({});
const env = new JSDomEnvironment(makeProjectConfig());

env1.fakeTimers.useFakeTimers();
env.fakeTimers!.useFakeTimers();

const timer1 = env1.global.setTimeout(() => {}, 0);
const timer2 = env1.global.setInterval(() => {}, 0);
const timer1 = env.global.setTimeout(() => {}, 0);
const timer2 = env.global.setInterval(() => {}, 0);

[timer1, timer2].forEach(timer => {
expect(typeof timer).toBe('number');
});
});

it('has Lolex fake timers implementation', () => {
const env = new JSDomEnvironment(makeProjectConfig());

expect(env.fakeTimersLolex).toBeDefined();
});
});
31 changes: 19 additions & 12 deletions packages/jest-environment-jsdom/src/index.ts
Expand Up @@ -8,8 +8,11 @@
import {Script} from 'vm';
import {Config, Global} from '@jest/types';
import {installCommonGlobals} from 'jest-util';
import mock = require('jest-mock');
import {JestFakeTimers as FakeTimers} from '@jest/fake-timers';
import {ModuleMocker} from 'jest-mock';
import {
JestFakeTimers as LegacyFakeTimers,
LolexFakeTimers,
} from '@jest/fake-timers';
import {EnvironmentContext, JestEnvironment} from '@jest/environment';
import {JSDOM, VirtualConsole} from 'jsdom';

Expand All @@ -24,10 +27,11 @@ type Win = Window &

class JSDOMEnvironment implements JestEnvironment {
dom: JSDOM | null;
fakeTimers: FakeTimers<number> | null;
fakeTimers: LegacyFakeTimers<number> | null;
fakeTimersLolex: LolexFakeTimers | null;
global: Win;
errorEventListener: ((event: Event & {error: Error}) => void) | null;
moduleMocker: mock.ModuleMocker | null;
moduleMocker: ModuleMocker | null;

constructor(config: Config.ProjectConfig, options: EnvironmentContext = {}) {
this.dom = new JSDOM('<!DOCTYPE html>', {
Expand Down Expand Up @@ -78,29 +82,32 @@ class JSDOMEnvironment implements JestEnvironment {
return originalRemoveListener.apply(this, args);
};

this.moduleMocker = new mock.ModuleMocker(global as any);
this.moduleMocker = new ModuleMocker(global as any);

const timerConfig = {
idToRef: (id: number) => id,
refToId: (ref: number) => ref,
};

this.fakeTimers = new FakeTimers({
this.fakeTimers = new LegacyFakeTimers({
config,
global: global as any,
global,
moduleMocker: this.moduleMocker,
timerConfig,
});
}

setup() {
return Promise.resolve();
this.fakeTimersLolex = new LolexFakeTimers({config, global});
}

teardown() {
async setup() {}

async teardown() {
if (this.fakeTimers) {
this.fakeTimers.dispose();
}
if (this.fakeTimersLolex) {
this.fakeTimersLolex.dispose();
}
if (this.global) {
if (this.errorEventListener) {
this.global.removeEventListener('error', this.errorEventListener);
Expand All @@ -114,7 +121,7 @@ class JSDOMEnvironment implements JestEnvironment {
this.global = null;
this.dom = null;
this.fakeTimers = null;
return Promise.resolve();
this.fakeTimersLolex = null;
}

runScript(script: Script) {
Expand Down
Expand Up @@ -4,42 +4,49 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const NodeEnvironment = jest.requireActual('../');
import NodeEnvironment = require('../');
import {makeProjectConfig} from '../../../../TestUtils';

describe('NodeEnvironment', () => {
it('uses a copy of the process object', () => {
const env1 = new NodeEnvironment({});
const env2 = new NodeEnvironment({});
const env1 = new NodeEnvironment(makeProjectConfig());
const env2 = new NodeEnvironment(makeProjectConfig());

expect(env1.global.process).not.toBe(env2.global.process);
});

it('exposes process.on', () => {
const env1 = new NodeEnvironment({});
const env1 = new NodeEnvironment(makeProjectConfig());

expect(env1.global.process.on).not.toBe(null);
});

it('exposes global.global', () => {
const env1 = new NodeEnvironment({});
const env1 = new NodeEnvironment(makeProjectConfig());

expect(env1.global.global).toBe(env1.global);
});

it('should configure setTimeout/setInterval to use the node api', () => {
const env1 = new NodeEnvironment({});
const env1 = new NodeEnvironment(makeProjectConfig());

env1.fakeTimers.useFakeTimers();
env1.fakeTimers!.useFakeTimers();

const timer1 = env1.global.setTimeout(() => {}, 0);
const timer2 = env1.global.setInterval(() => {}, 0);

[timer1, timer2].forEach(timer => {
// @ts-ignore
expect(timer.id).not.toBeUndefined();
expect(typeof timer.ref).toBe('function');
expect(typeof timer.unref).toBe('function');
});
});

it('has Lolex fake timers implementation', () => {
const env = new NodeEnvironment(makeProjectConfig());

expect(env.fakeTimersLolex).toBeDefined();
});
});
23 changes: 15 additions & 8 deletions packages/jest-environment-node/src/index.ts
Expand Up @@ -9,7 +9,10 @@ import {Context, Script, createContext, runInContext} from 'vm';
import {Config, Global} from '@jest/types';
import {ModuleMocker} from 'jest-mock';
import {installCommonGlobals} from 'jest-util';
import {JestFakeTimers as FakeTimers} from '@jest/fake-timers';
import {
JestFakeTimers as LegacyFakeTimers,
LolexFakeTimers,
} from '@jest/fake-timers';
import {JestEnvironment} from '@jest/environment';

type Timer = {
Expand All @@ -20,7 +23,8 @@ type Timer = {

class NodeEnvironment implements JestEnvironment {
context: Context | null;
fakeTimers: FakeTimers<Timer> | null;
fakeTimers: LegacyFakeTimers<Timer> | null;
fakeTimersLolex: LolexFakeTimers | null;
global: Global.Global;
moduleMocker: ModuleMocker | null;

Expand Down Expand Up @@ -70,25 +74,28 @@ class NodeEnvironment implements JestEnvironment {
refToId: timerRefToId,
};

this.fakeTimers = new FakeTimers({
this.fakeTimers = new LegacyFakeTimers({
config,
global,
moduleMocker: this.moduleMocker,
timerConfig,
});
}

setup() {
return Promise.resolve();
this.fakeTimersLolex = new LolexFakeTimers({config, global});
}

teardown() {
async setup() {}

async teardown() {
if (this.fakeTimers) {
this.fakeTimers.dispose();
}
if (this.fakeTimersLolex) {
this.fakeTimersLolex.dispose();
}
this.context = null;
this.fakeTimers = null;
return Promise.resolve();
this.fakeTimersLolex = null;
}

// TS infers the return type to be `any`, since that's what `runInContext`
Expand Down
8 changes: 6 additions & 2 deletions packages/jest-environment/src/index.ts
Expand Up @@ -9,7 +9,10 @@ import {Script} from 'vm';
import {Circus, Config, Global} from '@jest/types';
import jestMock = require('jest-mock');
import {ScriptTransformer} from '@jest/transform';
import {JestFakeTimers as FakeTimers} from '@jest/fake-timers';
import {
JestFakeTimers as LegacyFakeTimers,
LolexFakeTimers,
} from '@jest/fake-timers';

type JestMockFn = typeof jestMock.fn;
type JestMockSpyOn = typeof jestMock.spyOn;
Expand Down Expand Up @@ -37,7 +40,8 @@ export type ModuleWrapper = (
export declare class JestEnvironment {
constructor(config: Config.ProjectConfig, context?: EnvironmentContext);
global: Global.Global;
fakeTimers: FakeTimers<unknown> | null;
fakeTimers: LegacyFakeTimers<unknown> | null;
fakeTimersLolex: LolexFakeTimers | null;
moduleMocker: jestMock.ModuleMocker | null;
runScript(
script: Script,
Expand Down
8 changes: 4 additions & 4 deletions packages/jest-fake-timers/src/FakeTimersLolex.ts
Expand Up @@ -94,11 +94,11 @@ export default class FakeTimers {
}

useFakeTimers() {
const toFake = Object.keys(this._lolex.timers) as Array<
keyof LolexWithContext['timers']
>;

if (!this._fakingTime) {
const toFake = Object.keys(this._lolex.timers) as Array<
keyof LolexWithContext['timers']
>;

this._clock = this._lolex.install({
loopLimit: this._maxLoops,
now: Date.now(),
Expand Down
Expand Up @@ -55,7 +55,7 @@ Object {
"\\\\.test\\\\.js$",
],
"testRunner": "jest-jasmine2",
"testURL": "",
"testURL": "http://localhost",
"timers": "real",
"transform": Array [
Array [
Expand Down Expand Up @@ -218,7 +218,7 @@ exports[`ScriptTransformer uses multiple preprocessors 1`] = `
const TRANSFORMED = {
filename: '/fruits/banana.js',
script: 'module.exports = \\"banana\\";',
config: '{\\"automock\\":false,\\"browser\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"filter\\":null,\\"forceCoverageMatch\\":[],\\"globalSetup\\":null,\\"globalTeardown\\":null,\\"globals\\":{},\\"haste\\":{\\"providesModuleNodeModules\\":[]},\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"resolver\\":null,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"snapshotResolver\\":null,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"^.+\\\\\\\\.js$\\",\\"test_preprocessor\\"],[\\"^.+\\\\\\\\.css$\\",\\"css-preprocessor\\"]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"unmockedModulePathPatterns\\":null,\\"watchPathIgnorePatterns\\":[]}',
config: '{\\"automock\\":false,\\"browser\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"filter\\":null,\\"forceCoverageMatch\\":[],\\"globalSetup\\":null,\\"globalTeardown\\":null,\\"globals\\":{},\\"haste\\":{\\"providesModuleNodeModules\\":[]},\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"resolver\\":null,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"snapshotResolver\\":null,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"http://localhost\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"^.+\\\\\\\\.js$\\",\\"test_preprocessor\\"],[\\"^.+\\\\\\\\.css$\\",\\"css-preprocessor\\"]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"unmockedModulePathPatterns\\":null,\\"watchPathIgnorePatterns\\":[]}',
};
}});"
Expand All @@ -244,7 +244,7 @@ exports[`ScriptTransformer uses the supplied preprocessor 1`] = `
const TRANSFORMED = {
filename: '/fruits/banana.js',
script: 'module.exports = \\"banana\\";',
config: '{\\"automock\\":false,\\"browser\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"filter\\":null,\\"forceCoverageMatch\\":[],\\"globalSetup\\":null,\\"globalTeardown\\":null,\\"globals\\":{},\\"haste\\":{\\"providesModuleNodeModules\\":[]},\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"resolver\\":null,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"snapshotResolver\\":null,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"^.+\\\\\\\\.js$\\",\\"test_preprocessor\\"]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"unmockedModulePathPatterns\\":null,\\"watchPathIgnorePatterns\\":[]}',
config: '{\\"automock\\":false,\\"browser\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"filter\\":null,\\"forceCoverageMatch\\":[],\\"globalSetup\\":null,\\"globalTeardown\\":null,\\"globals\\":{},\\"haste\\":{\\"providesModuleNodeModules\\":[]},\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"resolver\\":null,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"snapshotResolver\\":null,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"http://localhost\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"^.+\\\\\\\\.js$\\",\\"test_preprocessor\\"]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"unmockedModulePathPatterns\\":null,\\"watchPathIgnorePatterns\\":[]}',
};
}});"
Expand Down

0 comments on commit 0935f7c

Please sign in to comment.