Skip to content

Commit

Permalink
feat(jest-environment): Pass global config to Jest environment constr…
Browse files Browse the repository at this point in the history
…uctor
  • Loading branch information
ahnpnl committed Feb 22, 2022
1 parent f9d4fc4 commit 3345cd7
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 79 deletions.
2 changes: 2 additions & 0 deletions e2e/test-environment/EsmDefaultEnvironment.js
Expand Up @@ -14,6 +14,8 @@ class Env extends NodeEnvironment {
constructor(config, options) {
super(config, options);
this.global.property = 'value';
this.global.var1 = config.globalConfig.watch;
this.global.var2 = config.projectConfig.cache;
}
}

Expand Down
2 changes: 2 additions & 0 deletions e2e/test-environment/__tests__/esmDefault.test.js
Expand Up @@ -10,4 +10,6 @@

test('access env', () => {
expect(property).toBe('value'); // eslint-disable-line no-undef
expect(var1).toBe(false); // eslint-disable-line no-undef
expect(var2).toBe(true); // eslint-disable-line no-undef
});
Expand Up @@ -5,12 +5,15 @@
* LICENSE file in the root directory of this source tree.
*/

import {makeProjectConfig} from '@jest/test-utils';
import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils';
import JSDomEnvironment from '../';

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

env.fakeTimers!.useFakeTimers();

Expand All @@ -23,19 +26,23 @@ describe('JSDomEnvironment', () => {
});

it('has modern fake timers implementation', () => {
const env = new JSDomEnvironment(makeProjectConfig());
const env = new JSDomEnvironment({
globalConfig: makeGlobalConfig(),
projectConfig: makeProjectConfig(),
});

expect(env.fakeTimersModern).toBeDefined();
});

it('should respect userAgent option', () => {
const env = new JSDomEnvironment(
makeProjectConfig({
const env = new JSDomEnvironment({
globalConfig: makeGlobalConfig(),
projectConfig: makeProjectConfig({
testEnvironmentOptions: {
userAgent: 'foo',
},
}),
);
});

expect(env.dom.window.navigator.userAgent).toEqual('foo');
});
Expand All @@ -53,7 +60,10 @@ describe('JSDomEnvironment', () => {
* will be called, so please make sure the global.document is still available at this point.
*/
it('should not set the global.document to null too early', () => {
const env = new JSDomEnvironment(makeProjectConfig());
const env = new JSDomEnvironment({
globalConfig: makeGlobalConfig(),
projectConfig: makeProjectConfig(),
});

const originalCloseFn = env.global.close.bind(env.global);
env.global.close = () => {
Expand Down
29 changes: 17 additions & 12 deletions packages/jest-environment-jsdom/src/index.ts
Expand Up @@ -7,9 +7,13 @@

import type {Context} from 'vm';
import {JSDOM, ResourceLoader, VirtualConsole} from 'jsdom';
import type {EnvironmentContext, JestEnvironment} from '@jest/environment';
import type {
EnvironmentContext,
JestEnvironment,
JestEnvironmentConfig,
} from '@jest/environment';
import {LegacyFakeTimers, ModernFakeTimers} from '@jest/fake-timers';
import type {Config, Global} from '@jest/types';
import type {Global} from '@jest/types';
import {ModuleMocker} from 'jest-mock';
import {installCommonGlobals} from 'jest-util';

Expand All @@ -30,25 +34,26 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
private errorEventListener: ((event: Event & {error: Error}) => void) | null;
moduleMocker: ModuleMocker | null;

constructor(config: Config.ProjectConfig, options?: EnvironmentContext) {
constructor(config: JestEnvironmentConfig, options?: EnvironmentContext) {
const {projectConfig} = config;
this.dom = new JSDOM(
typeof config.testEnvironmentOptions.html === 'string'
? config.testEnvironmentOptions.html
typeof projectConfig.testEnvironmentOptions.html === 'string'
? projectConfig.testEnvironmentOptions.html
: '<!DOCTYPE html>',
{
pretendToBeVisual: true,
resources:
typeof config.testEnvironmentOptions.userAgent === 'string'
typeof projectConfig.testEnvironmentOptions.userAgent === 'string'
? new ResourceLoader({
userAgent: config.testEnvironmentOptions.userAgent,
userAgent: projectConfig.testEnvironmentOptions.userAgent,
})
: undefined,
runScripts: 'dangerously',
url: config.testURL,
url: projectConfig.testURL,
virtualConsole: new VirtualConsole().sendTo(
options?.console || console,
),
...config.testEnvironmentOptions,
...projectConfig.testEnvironmentOptions,
},
);
const global = (this.global = this.dom.window.document
Expand All @@ -64,7 +69,7 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
// Node's error-message stack size is limited at 10, but it's pretty useful
// to see more than that when a test fails.
this.global.Error.stackTraceLimit = 100;
installCommonGlobals(global as any, config.globals);
installCommonGlobals(global as any, projectConfig.globals);

// TODO: remove this ASAP, but it currently causes tests to run really slow
global.Buffer = Buffer;
Expand Down Expand Up @@ -107,14 +112,14 @@ export default class JSDOMEnvironment implements JestEnvironment<number> {
};

this.fakeTimers = new LegacyFakeTimers({
config,
config: projectConfig,
global: global as unknown as typeof globalThis,
moduleMocker: this.moduleMocker,
timerConfig,
});

this.fakeTimersModern = new ModernFakeTimers({
config,
config: projectConfig,
global: global as unknown as typeof globalThis,
});
}
Expand Down
Expand Up @@ -5,31 +5,44 @@
* LICENSE file in the root directory of this source tree.
*/

import {makeProjectConfig} from '@jest/test-utils';
import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils';
import NodeEnvironment from '../';

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

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

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

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

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

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

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

env1.fakeTimers!.useFakeTimers();

Expand All @@ -44,7 +57,10 @@ describe('NodeEnvironment', () => {
});

it('has modern fake timers implementation', () => {
const env = new NodeEnvironment(makeProjectConfig());
const env = new NodeEnvironment({
globalConfig: makeGlobalConfig(),
projectConfig: makeProjectConfig(),
});

expect(env.fakeTimersModern).toBeDefined();
});
Expand Down
18 changes: 11 additions & 7 deletions packages/jest-environment-node/src/index.ts
Expand Up @@ -6,9 +6,9 @@
*/

import {Context, createContext, runInContext} from 'vm';
import type {JestEnvironment} from '@jest/environment';
import type {JestEnvironment, JestEnvironmentConfig} from '@jest/environment';
import {LegacyFakeTimers, ModernFakeTimers} from '@jest/fake-timers';
import type {Config, Global} from '@jest/types';
import type {Global} from '@jest/types';
import {ModuleMocker} from 'jest-mock';
import {installCommonGlobals} from 'jest-util';

Expand All @@ -25,11 +25,12 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
global: Global.Global;
moduleMocker: ModuleMocker | null;

constructor(config: Config.ProjectConfig) {
constructor(config: JestEnvironmentConfig) {
const {projectConfig} = config;
this.context = createContext();
const global = (this.global = runInContext(
'this',
Object.assign(this.context, config.testEnvironmentOptions),
Object.assign(this.context, projectConfig.testEnvironmentOptions),
));
global.global = global;
global.clearInterval = clearInterval;
Expand Down Expand Up @@ -81,7 +82,7 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
global.atob = atob;
global.btoa = btoa;
}
installCommonGlobals(global, config.globals);
installCommonGlobals(global, projectConfig.globals);

this.moduleMocker = new ModuleMocker(global);

Expand All @@ -104,13 +105,16 @@ export default class NodeEnvironment implements JestEnvironment<Timer> {
};

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

this.fakeTimersModern = new ModernFakeTimers({config, global});
this.fakeTimersModern = new ModernFakeTimers({
config: projectConfig,
global,
});
}

async setup(): Promise<void> {}
Expand Down
7 changes: 6 additions & 1 deletion packages/jest-environment/src/index.ts
Expand Up @@ -28,8 +28,13 @@ export type ModuleWrapper = (
...extraGlobals: Array<Global.Global[keyof Global.Global]>
) => unknown;

export interface JestEnvironmentConfig {
projectConfig: Config.ProjectConfig;
globalConfig: Config.GlobalConfig;
}

export declare class JestEnvironment<Timer = unknown> {
constructor(config: Config.ProjectConfig, context?: EnvironmentContext);
constructor(config: JestEnvironmentConfig, context?: EnvironmentContext);
global: Global.Global;
fakeTimers: LegacyFakeTimers<Timer> | null;
fakeTimersModern: ModernFakeTimers | null;
Expand Down
21 changes: 13 additions & 8 deletions packages/jest-repl/src/cli/runtime-cli.ts
Expand Up @@ -63,22 +63,27 @@ export async function run(
const options = await readConfig(argv, root);
const globalConfig = options.globalConfig;
// Always disable automocking in scripts.
const config: Config.ProjectConfig = {
const projectConfig: Config.ProjectConfig = {
...options.projectConfig,
automock: false,
};

try {
const hasteMap = await Runtime.createContext(config, {
const hasteMap = await Runtime.createContext(projectConfig, {
maxWorkers: Math.max(cpus().length - 1, 1),
watchman: globalConfig.watchman,
});

const transformer = await createScriptTransformer(config);
const transformer = await createScriptTransformer(projectConfig);
const Environment: typeof JestEnvironment =
await transformer.requireAndTranspileModule(config.testEnvironment);
await transformer.requireAndTranspileModule(
projectConfig.testEnvironment,
);

const environment = new Environment(config);
const environment = new Environment({
globalConfig,
projectConfig,
});
setGlobal(
environment.global as unknown as typeof globalThis,
'console',
Expand All @@ -87,7 +92,7 @@ export async function run(
setGlobal(
environment.global as unknown as typeof globalThis,
'jestProjectConfig',
config,
projectConfig,
);
setGlobal(
environment.global as unknown as typeof globalThis,
Expand All @@ -96,7 +101,7 @@ export async function run(
);

const runtime = new Runtime(
config,
projectConfig,
environment,
hasteMap.resolver,
transformer,
Expand All @@ -112,7 +117,7 @@ export async function run(
filePath,
);

for (const path of config.setupFiles) {
for (const path of projectConfig.setupFiles) {
const esm = runtime.unstable_shouldLoadAsEsm(path);

if (esm) {
Expand Down

0 comments on commit 3345cd7

Please sign in to comment.