From 40224044ef128096ecf97a0d8ba891330aee4dd8 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 1 Dec 2019 14:35:13 +0100 Subject: [PATCH] feat: add support for avoiding the module wrapper --- CHANGELOG.md | 2 + TestUtils.ts | 1 + .../__snapshots__/showConfig.test.ts.snap | 1 + packages/jest-cli/src/cli/args.ts | 5 ++ packages/jest-config/src/Defaults.ts | 1 + packages/jest-config/src/ValidConfig.ts | 1 + packages/jest-config/src/index.ts | 1 + packages/jest-config/src/normalize.ts | 1 + .../log_debug_messages.test.ts.snap | 1 + packages/jest-environment-jsdom/src/index.ts | 8 +++ packages/jest-environment-node/src/index.ts | 24 ++++++++- packages/jest-environment/src/index.ts | 5 ++ packages/jest-runtime/src/index.ts | 49 +++++++++++++------ packages/jest-types/src/Config.ts | 3 ++ 14 files changed, 88 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f22279851bf..8856d5fa0e1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - `[jest-diff]` Add `changeColor` and `patchColor` options ([#8911](https://github.com/facebook/jest/pull/8911)) - `[jest-diff]` Add `trailingSpaceFormatter` option and replace cyan with `commonColor` ([#8927](https://github.com/facebook/jest/pull/8927)) - `[jest-diff]` Add `firstOrLastEmptyLineReplacement` option and export 3 `diffLines` functions ([#8955](https://github.com/facebook/jest/pull/8955)) +- `[jest-environment]` Support compiling a function, rather than using a module wrapper ([#9252](https://github.com/facebook/jest/pull/9252)) - `[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-environment-node]` Add `queueMicrotask` ([#9140](https://github.com/facebook/jest/pull/9140)) @@ -26,6 +27,7 @@ - `[jest-reporters]` Export utils for path formatting ([#9162](https://github.com/facebook/jest/pull/9162)) - `[jest-runner]` Warn if a worker had to be force exited ([#8206](https://github.com/facebook/jest/pull/8206)) - `[jest-runtime]` [**BREAKING**] Do not export `ScriptTransformer` - it can be imported from `@jest/transform` instead ([#9256](https://github.com/facebook/jest/pull/9256)) +- `[jest-runtime]` Support compiling a function, rather than using a module wrapper ([#9252](https://github.com/facebook/jest/pull/9252)) - `[jest-snapshot]` Display change counts in annotation lines ([#8982](https://github.com/facebook/jest/pull/8982)) - `[jest-snapshot]` [**BREAKING**] Improve report when the matcher has properties ([#9104](https://github.com/facebook/jest/pull/9104)) - `[jest-snapshot]` Improve colors when snapshots are updatable ([#9132](https://github.com/facebook/jest/pull/9132)) diff --git a/TestUtils.ts b/TestUtils.ts index aa4f3c345dca..95724c500fbf 100644 --- a/TestUtils.ts +++ b/TestUtils.ts @@ -92,6 +92,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = { moduleNameMapper: [], modulePathIgnorePatterns: [], modulePaths: [], + moduleWrapper: true, name: 'test_name', prettierPath: 'prettier', resetMocks: false, diff --git a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap index e7bd2b9c3273..b44b32572a0c 100644 --- a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap +++ b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap @@ -37,6 +37,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` ], "moduleNameMapper": [], "modulePathIgnorePatterns": [], + "moduleWrapper": true, "name": "[md5 hash]", "prettierPath": "prettier", "resetMocks": false, diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index 6bc9650b7a01..5d01c123756a 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -392,6 +392,11 @@ export const options = { string: true, type: 'array', }, + moduleWrapper: { + default: true, + description: 'Wrap transformed modules', + type: 'boolean' as 'boolean', + }, noStackTrace: { default: undefined, description: 'Disables stack trace in test results output', diff --git a/packages/jest-config/src/Defaults.ts b/packages/jest-config/src/Defaults.ts index e096029b7795..765e036460da 100644 --- a/packages/jest-config/src/Defaults.ts +++ b/packages/jest-config/src/Defaults.ts @@ -38,6 +38,7 @@ const defaultOptions: Config.DefaultOptions = { moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node'], moduleNameMapper: {}, modulePathIgnorePatterns: [], + moduleWrapper: true, noStackTrace: false, notify: false, notifyMode: 'failure-change', diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index 28178876d529..8b17a4937b34 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -72,6 +72,7 @@ const initialOptions: Config.InitialOptions = { }, modulePathIgnorePatterns: ['/build/'], modulePaths: ['/shared/vendor/modules'], + moduleWrapper: false, name: 'string', noStackTrace: false, notify: false, diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index eb392317c02b..38014e994b4b 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -184,6 +184,7 @@ const groupOptions = ( moduleNameMapper: options.moduleNameMapper, modulePathIgnorePatterns: options.modulePathIgnorePatterns, modulePaths: options.modulePaths, + moduleWrapper: options.moduleWrapper, name: options.name, prettierPath: options.prettierPath, resetMocks: options.resetMocks, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 96111241f9d3..20aacb15901a 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -852,6 +852,7 @@ export default function normalize( case 'logHeapUsage': case 'maxConcurrency': case 'mapCoverage': + case 'moduleWrapper': case 'name': case 'noStackTrace': case 'notify': diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap index 0f4ceaeb6a3b..4a5313ae5757 100644 --- a/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap +++ b/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap @@ -30,6 +30,7 @@ exports[`prints the config object 1`] = ` "moduleNameMapper": [], "modulePathIgnorePatterns": [], "modulePaths": [], + "moduleWrapper": true, "name": "test_name", "prettierPath": "prettier", "resetMocks": false, diff --git a/packages/jest-environment-jsdom/src/index.ts b/packages/jest-environment-jsdom/src/index.ts index 557afc1a6b36..31f35ad8bcf3 100644 --- a/packages/jest-environment-jsdom/src/index.ts +++ b/packages/jest-environment-jsdom/src/index.ts @@ -130,6 +130,14 @@ class JSDOMEnvironment implements JestEnvironment { } return null; } + + compileFunction(code: string, params: Array, filename: string) { + if (this.dom) { + // @ts-ignore + return this.dom.compileFunction(code, params, {filename}) as any; + } + return null; + } } export = JSDOMEnvironment; diff --git a/packages/jest-environment-node/src/index.ts b/packages/jest-environment-node/src/index.ts index 897c3734c784..c8190839ae36 100644 --- a/packages/jest-environment-node/src/index.ts +++ b/packages/jest-environment-node/src/index.ts @@ -5,7 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -import {Context, Script, createContext, runInContext} from 'vm'; +import { + Context, + Script, + compileFunction, + createContext, + runInContext, +} from 'vm'; import {Config, Global} from '@jest/types'; import {ModuleMocker} from 'jest-mock'; import {installCommonGlobals} from 'jest-util'; @@ -110,6 +116,22 @@ class NodeEnvironment implements JestEnvironment { } return null; } + + compileFunction(code: string, params: Array, filename: string) { + if (!compileFunction) { + throw new TypeError( + "The version of Node you're using does not support compileFunction, please upgrade", + ); + } + + if (this.context) { + return compileFunction(code, params, { + filename, + parsingContext: this.context, + }) as any; + } + return null; + } } export = NodeEnvironment; diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index d28dba5dda70..14a61655e110 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -44,6 +44,11 @@ export declare class JestEnvironment { fakeTimersLolex: LolexFakeTimers | null; moduleMocker: jestMock.ModuleMocker | null; runScript(script: Script): T | null; + compileFunction( + code: string, + params: Array, + filename: string, + ): T | null; setup(): Promise; teardown(): Promise; handleTestEvent?(event: Circus.Event, state: Circus.State): void; diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index d33f5570e9fe..207690216c42 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -730,11 +730,29 @@ class Runtime { } } - const script = this.createScriptFromCode(transformedFile.code, filename); + let compiledFunction: ModuleWrapper | null; - const runScript = this._environment.runScript(script); + if (this._config.moduleWrapper) { + const script = this.createScriptFromCode(transformedFile.code, filename); - if (runScript === null) { + const runScript = this._environment.runScript( + script, + ); + + if (runScript === null) { + compiledFunction = null; + } else { + compiledFunction = runScript[EVAL_RESULT_VARIABLE]; + } + } else { + compiledFunction = this._environment.compileFunction( + transformedFile.code, + this.constructInjectedModuleParameters(), + filename, + ); + } + + if (compiledFunction === null) { this._logFormattedReferenceError( 'You are trying to `import` a file after the Jest environment has been torn down.', ); @@ -742,8 +760,7 @@ class Runtime { return; } - //Wrapper - runScript[EVAL_RESULT_VARIABLE].call( + compiledFunction.call( localModule.exports, localModule as NodeModule, // module object localModule.exports, // module exports @@ -1107,7 +1124,19 @@ class Runtime { } private wrapCodeInModuleWrapper(content: string) { - const args = [ + const args = this.constructInjectedModuleParameters(); + + return ( + '({"' + + EVAL_RESULT_VARIABLE + + `":function(${args.join(',')}){` + + content + + '\n}});' + ); + } + + private constructInjectedModuleParameters() { + return [ 'module', 'exports', 'require', @@ -1117,14 +1146,6 @@ class Runtime { 'jest', ...this._config.extraGlobals, ]; - - return ( - '({"' + - EVAL_RESULT_VARIABLE + - `":function(${args.join(',')}){` + - content + - '\n}});' - ); } } diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index aca89876a7c1..ebb564c617fe 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -49,6 +49,7 @@ export type DefaultOptions = { moduleFileExtensions: Array; moduleNameMapper: Record; modulePathIgnorePatterns: Array; + moduleWrapper: boolean; noStackTrace: boolean; notify: boolean; notifyMode: NotifyMode; @@ -143,6 +144,7 @@ export type InitialOptions = Partial<{ }; modulePathIgnorePatterns: Array; modulePaths: Array; + moduleWrapper: boolean; name: string; noStackTrace: boolean; notify: boolean; @@ -318,6 +320,7 @@ export type ProjectConfig = { moduleNameMapper: Array<[string, string]>; modulePathIgnorePatterns: Array; modulePaths?: Array; + moduleWrapper: boolean; name: string; prettierPath: string; resetMocks: boolean;