Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fakeTimersLolex to the test environments #8925

Merged
merged 2 commits into from
Sep 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = {
testPathIgnorePatterns: [],
testRegex: ['\\.test\\.js$'],
testRunner: 'jest-jasmine2',
testURL: '',
testURL: 'http://localhost',
thymikee marked this conversation as resolved.
Show resolved Hide resolved
timers: 'real',
transform: [],
transformIgnorePatterns: [],
Expand Down
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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