From 5c2ebceb254901059ff5e2eacdbd9ac3f23b87dd Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 11 Feb 2017 00:45:27 +0100 Subject: [PATCH] Allow setting a test environment per file --- docs/Configuration.md | 13 +- .../__tests__/test-environment-test.js | 26 ++++ .../test-environment/__tests__/env-test.js | 19 +++ .../test-environment/package.json | 5 + packages/jest-cli/src/runTest.js | 127 ++++++++++-------- packages/jest-config/src/index.js | 2 + 6 files changed, 136 insertions(+), 56 deletions(-) create mode 100644 integration_tests/__tests__/test-environment-test.js create mode 100644 integration_tests/test-environment/__tests__/env-test.js create mode 100644 integration_tests/test-environment/package.json diff --git a/docs/Configuration.md b/docs/Configuration.md index 6755ecd34690..5a016dc2ba3c 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -318,7 +318,18 @@ To make a dependency explicit instead of implicit, you can call [`expect.addSnap ### `testEnvironment` [string] Default: `"jsdom"` -The test environment that will be used for testing. The default environment in Jest is a browser-like environment through [jsdom](https://github.com/tmpvar/jsdom). If you are building a node service, you can use the `node` option to use a node-like environment instead. Combining the test environments is currently not possible but the `jsdom` environment can be seen as a superset of the `node` one. +The test environment that will be used for testing. The default environment in Jest is a browser-like environment through [jsdom](https://github.com/tmpvar/jsdom). If you are building a node service, you can use the `node` option to use a node-like environment instead. If some tests require another environment, you can add a `@testEnvironment` pragma. + +```js +/** + * @testEnvironment jsdom + */ + +test('use document in a mostly node environment', () => { + const ele = document.createElement('div'); + expect(ele).not.toBeNull(); +}); +``` You can create your own module that will be used for setting up the test environment. The module must export a class with `runScript` and `dispose` methods. See the [node](https://github.com/facebook/jest/blob/master/packages/jest-environment-node/src/index.js) or [jsdom](https://github.com/facebook/jest/blob/master/packages/jest-environment-jsdom/src/index.js) environments as examples. diff --git a/integration_tests/__tests__/test-environment-test.js b/integration_tests/__tests__/test-environment-test.js new file mode 100644 index 000000000000..935600b88e07 --- /dev/null +++ b/integration_tests/__tests__/test-environment-test.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails oncall+jsinfra + */ +'use strict'; + +const runJest = require('../runJest'); +const skipOnWindows = require('skipOnWindows'); + +skipOnWindows.suite(); + +const testFixturePackage = require('../test-environment/package.json'); + +it('respects testEnvironment pragma', () => { + expect(testFixturePackage.jest.testEnvironment).toEqual('node'); + + const result = runJest.json('test-environment').json; + + expect(result.success).toBe(true); + expect(result.numTotalTests).toBe(1); +}); diff --git a/integration_tests/test-environment/__tests__/env-test.js b/integration_tests/test-environment/__tests__/env-test.js new file mode 100644 index 000000000000..3048de141190 --- /dev/null +++ b/integration_tests/test-environment/__tests__/env-test.js @@ -0,0 +1,19 @@ +/* eslint-env browser */ + +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +/** + * @testEnvironment jsdom + */ + +test('stub', () => { + const ele = document.createElement('div'); + expect(ele).not.toBeNull(); +}); diff --git a/integration_tests/test-environment/package.json b/integration_tests/test-environment/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/integration_tests/test-environment/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/packages/jest-cli/src/runTest.js b/packages/jest-cli/src/runTest.js index 19027e4f679a..b57a3b3a75fc 100644 --- a/packages/jest-cli/src/runTest.js +++ b/packages/jest-cli/src/runTest.js @@ -13,7 +13,10 @@ import type {Path, Config} from 'types/Config'; import type {TestResult} from 'types/TestResult'; import type {Resolver} from 'types/Resolve'; +const fs = require('fs'); +const {getTestEnvironment} = require('jest-config'); const BufferedConsole = require('./lib/BufferedConsole'); +const promisify = require('./lib/promisify'); const { Console, NullConsole, @@ -21,66 +24,80 @@ const { } = require('jest-util'); const getConsoleOutput = require('./reporters/getConsoleOutput'); +const testEnvironmentPragmaRegex = /@testEnvironment\s+(.*)/; + function runTest(path: Path, config: Config, resolver: Resolver) { - /* $FlowFixMe */ - const TestEnvironment = require(config.testEnvironment); - /* $FlowFixMe */ - const TestRunner = require(config.testRunner); - /* $FlowFixMe */ - const ModuleLoader = require(config.moduleLoader || 'jest-runtime'); + return promisify(fs.readFile)(path, 'utf8').then(data => { + let testEnvironment = config.testEnvironment; + + const testEnvironmentPragma = data.match(testEnvironmentPragmaRegex); - const env = new TestEnvironment(config); - const TestConsole = - config.verbose - ? Console - : (config.silent - ? NullConsole - : BufferedConsole + if (testEnvironmentPragma && testEnvironmentPragma.length > 1) { + testEnvironment = getTestEnvironment( + Object.assign({}, config, {testEnvironment: testEnvironmentPragma[1]}) ); - const testConsole = new TestConsole( - config.useStderr ? process.stderr : process.stdout, - process.stderr, - (type, message) => getConsoleOutput( - config.rootDir, - !!config.verbose, - // 4 = the console call is burried 4 stack frames deep - BufferedConsole.write([], type, message, 4), - ), - ); - setGlobal(env.global, 'console', testConsole); - const runtime = new ModuleLoader(config, env, resolver); - const start = Date.now(); - return TestRunner(config, env, runtime, path) - .then((result: TestResult) => { - const testCount = - result.numPassingTests + - result.numFailingTests + - result.numPendingTests; - result.perfStats = {end: Date.now(), start}; - result.testFilePath = path; - result.coverage = runtime.getAllCoverageInfo(); - result.console = testConsole.getBuffer(); - result.skipped = testCount === result.numPendingTests; - return result; - }) - .then( - result => Promise.resolve().then(() => { - env.dispose(); - if (config.logHeapUsage) { - if (global.gc) { - global.gc(); - } - result.memoryUsage = process.memoryUsage().heapUsed; - } + } + + /* $FlowFixMe */ + const TestEnvironment = require(testEnvironment); + /* $FlowFixMe */ + const TestRunner = require(config.testRunner); + /* $FlowFixMe */ + const ModuleLoader = require(config.moduleLoader || 'jest-runtime'); - // Delay the resolution to allow log messages to be output. - return new Promise(resolve => setImmediate(() => resolve(result))); - }), - err => Promise.resolve().then(() => { - env.dispose(); - throw err; - }), + const env = new TestEnvironment(config); + const TestConsole = + config.verbose + ? Console + : (config.silent + ? NullConsole + : BufferedConsole + ); + const testConsole = new TestConsole( + config.useStderr ? process.stderr : process.stdout, + process.stderr, + (type, message) => getConsoleOutput( + config.rootDir, + !!config.verbose, + // 4 = the console call is buried 4 stack frames deep + BufferedConsole.write([], type, message, 4), + ), ); + setGlobal(env.global, 'console', testConsole); + const runtime = new ModuleLoader(config, env, resolver); + const start = Date.now(); + return TestRunner(config, env, runtime, path) + .then((result: TestResult) => { + const testCount = + result.numPassingTests + + result.numFailingTests + + result.numPendingTests; + result.perfStats = {end: Date.now(), start}; + result.testFilePath = path; + result.coverage = runtime.getAllCoverageInfo(); + result.console = testConsole.getBuffer(); + result.skipped = testCount === result.numPendingTests; + return result; + }) + .then( + result => Promise.resolve().then(() => { + env.dispose(); + if (config.logHeapUsage) { + if (global.gc) { + global.gc(); + } + result.memoryUsage = process.memoryUsage().heapUsed; + } + + // Delay the resolution to allow log messages to be output. + return new Promise(resolve => setImmediate(() => resolve(result))); + }), + err => Promise.resolve().then(() => { + env.dispose(); + throw err; + }), + ); + }); } module.exports = runTest; diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index be32dff8f93c..d3198a09e43b 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -15,6 +15,7 @@ const loadFromFile = require('./loadFromFile'); const loadFromPackage = require('./loadFromPackage'); const normalize = require('./normalize'); const setFromArgv = require('./setFromArgv'); +const {getTestEnvironment} = require('./utils'); const readConfig = (argv: Object, packageRoot: string) => readRawConfig(argv, packageRoot) @@ -60,6 +61,7 @@ const readRawConfig = (argv, root) => { }; module.exports = { + getTestEnvironment, normalize, readConfig, };