From 170eee11d03b0ed5c60077982fdbc3bafd403638 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 21 Jan 2020 15:59:36 +0100 Subject: [PATCH] fix: expose vm context directly from test envs (#9428) --- CHANGELOG.md | 6 +-- packages/jest-environment-node/src/index.ts | 24 ++--------- packages/jest-environment/package.json | 3 ++ packages/jest-environment/src/index.ts | 11 +++-- packages/jest-runner/src/runTest.ts | 6 ++- packages/jest-runtime/src/index.ts | 47 ++++++++++++++++----- 6 files changed, 54 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d617f54617b..47a991643045 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,11 +21,11 @@ - `[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]` Add optional `compileFunction` next to `runScript` ([#9252](https://github.com/facebook/jest/pull/9252)) +- `[jest-environment]` Add optional `getVmContext` next to `runScript` ([#9252](https://github.com/facebook/jest/pull/9252) & [#9428](https://github.com/facebook/jest/pull/9428)) - `[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)) -- `[jest-environment-node]` Implement `compileFunction` ([#9140](https://github.com/facebook/jest/pull/9140)) +- `[jest-environment-node]` Implement `getVmContext` ([#9252](https://github.com/facebook/jest/pull/9252) & [#9428](https://github.com/facebook/jest/pull/9428)) - `[@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)) @@ -34,7 +34,7 @@ - `[jest-reporters]` Provides global coverage thresholds as watermarks for istanbul ([#9416](https://github.com/facebook/jest/pull/9416)) - `[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]` Use `JestEnvironment.compileFunction` if available to avoid the module wrapper ([#9252](https://github.com/facebook/jest/pull/9252)) +- `[jest-runtime]` Use `JestEnvironment.getVmContext` and `vm.compileFunction` if available to avoid the module wrapper ([#9252](https://github.com/facebook/jest/pull/9252) & [#9428](https://github.com/facebook/jest/pull/9428)) - `[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/packages/jest-environment-node/src/index.ts b/packages/jest-environment-node/src/index.ts index a3166920ceed..f8cce7d628dc 100644 --- a/packages/jest-environment-node/src/index.ts +++ b/packages/jest-environment-node/src/index.ts @@ -5,13 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - Context, - Script, - compileFunction, - createContext, - runInContext, -} from 'vm'; +import {Context, Script, createContext, runInContext} from 'vm'; import {Config, Global} from '@jest/types'; import {ModuleMocker} from 'jest-mock'; import {installCommonGlobals} from 'jest-util'; @@ -122,21 +116,9 @@ class NodeEnvironment implements JestEnvironment { return null; } - compileFunction(code: string, params: Array, filename: string) { - if (this.context) { - return compileFunction(code, params, { - filename, - parsingContext: this.context, - }) as any; - } - return null; + getVmContext() { + return this.context; } } -// `jest-runtime` checks for `compileFunction`, so this makes sure to not expose that function if it's unsupported by this version of node -// Should be removed when we drop support for node 8 -if (typeof compileFunction !== 'function') { - delete NodeEnvironment.prototype.compileFunction; -} - export = NodeEnvironment; diff --git a/packages/jest-environment/package.json b/packages/jest-environment/package.json index 8ec71969c536..8b6eac150103 100644 --- a/packages/jest-environment/package.json +++ b/packages/jest-environment/package.json @@ -14,6 +14,9 @@ "@jest/types": "^24.9.0", "jest-mock": "^24.9.0" }, + "devDependencies": { + "@types/node": "*" + }, "engines": { "node": ">= 8.3" }, diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index 5f265aba0b65..6f5c311189d0 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {Script} from 'vm'; +import {Context, Script} from 'vm'; import {Circus, Config, Global} from '@jest/types'; import jestMock = require('jest-mock'); import { @@ -43,12 +43,11 @@ export declare class JestEnvironment { fakeTimers: LegacyFakeTimers | null; fakeTimersLolex: LolexFakeTimers | null; moduleMocker: jestMock.ModuleMocker | null; + /** + * @deprecated implement getVmContext instead + */ runScript(script: Script): T | null; - compileFunction?( - code: string, - params: Array, - filename: string, - ): T | null; + getVmContext?(): Context | null; setup(): Promise; teardown(): Promise; handleTestEvent?(event: Circus.Event, state: Circus.State): void; diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 5d0232a28c08..d437d64f38eb 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -6,6 +6,7 @@ * */ +import {compileFunction} from 'vm'; import {Config} from '@jest/types'; import {TestResult} from '@jest/test-result'; import { @@ -219,10 +220,11 @@ async function runTestInternal( }; } - // if we don't have `compileFunction` on the env, skip coverage + // if we don't have `getVmContext` on the env,or `compileFunction` available skip coverage const collectV8Coverage = globalConfig.coverageProvider === 'v8' && - typeof environment.compileFunction === 'function'; + typeof environment.getVmContext === 'function' && + typeof compileFunction === 'function'; try { await environment.setup(); diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 7ce252df27e6..7ff305104da9 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -6,7 +6,7 @@ */ import * as path from 'path'; -import {Script} from 'vm'; +import {Script, compileFunction} from 'vm'; import {fileURLToPath} from 'url'; import {Config} from '@jest/types'; import { @@ -783,17 +783,42 @@ class Runtime { } } - let compiledFunction: ModuleWrapper | null; + let compiledFunction: ModuleWrapper | null = null; + + // Use this if available instead of deprecated `JestEnvironment.runScript` + if (typeof this._environment.getVmContext === 'function') { + const vmContext = this._environment.getVmContext(); + + if (vmContext) { + if (typeof compileFunction === 'function') { + try { + compiledFunction = compileFunction( + transformedFile.code, + this.constructInjectedModuleParameters(), + { + filename, + parsingContext: vmContext, + }, + ) as ModuleWrapper; + } catch (e) { + throw handlePotentialSyntaxError(e); + } + } else { + const script = this.createScriptFromCode( + transformedFile.code, + filename, + ); - if (typeof this._environment.compileFunction === 'function') { - try { - compiledFunction = this._environment.compileFunction( - transformedFile.code, - this.constructInjectedModuleParameters(), - filename, - ); - } catch (e) { - throw handlePotentialSyntaxError(e); + const runScript = script.runInContext( + vmContext, + ) as RunScriptEvalResult; + + if (runScript === null) { + compiledFunction = null; + } else { + compiledFunction = runScript[EVAL_RESULT_VARIABLE]; + } + } } } else { const script = this.createScriptFromCode(transformedFile.code, filename);