From e776fdddbe48af7315f81150c8531044fe07a3e9 Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Fri, 5 Jan 2018 12:20:34 -0700 Subject: [PATCH] pass testConsole to TestEnvironment (#5227) --- CHANGELOG.md | 6 +++ .../__snapshots__/console.test.js.snap | 18 +++++++++ integration_tests/__tests__/console.test.js | 11 +++++ .../console-jsdom/__tests__/console.test.js | 40 +++++++++++++++++++ integration_tests/console-jsdom/package.json | 5 +++ packages/jest-environment-jsdom/src/index.js | 8 +++- packages/jest-runner/src/run_test.js | 10 ++--- types/Environment.js | 6 ++- 8 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 integration_tests/console-jsdom/__tests__/console.test.js create mode 100644 integration_tests/console-jsdom/package.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 395c02eed0ca..9c52cde971e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,12 @@ * `[docs]` Add documentation for .toHaveProperty matcher to accept the keyPath argument as an array of properties/indices. ([#5220](https://github.com/facebook/jest/pull/5220)) +* `[jest-runner]` test environments are now passed a new `options` parameter. + Currently this only has the `console` which is the test console that Jest will + expose to tests. ([#5223](https://github.com/facebook/jest/issues/5223)) +* `[jest-environment-jsdom]` pass the `options.console` to a custom + instance of `virtualConsole` so jsdom is using the same console as the + test. ([#5223](https://github.com/facebook/jest/issues/5223)) ### Chore & Maintenance diff --git a/integration_tests/__tests__/__snapshots__/console.test.js.snap b/integration_tests/__tests__/__snapshots__/console.test.js.snap index 425f59ac421b..517a497995b3 100644 --- a/integration_tests/__tests__/__snapshots__/console.test.js.snap +++ b/integration_tests/__tests__/__snapshots__/console.test.js.snap @@ -73,3 +73,21 @@ Snapshots: 0 total Time: <> " `; + +exports[`the jsdom console is the same as the test console 1`] = `""`; + +exports[`the jsdom console is the same as the test console 2`] = ` +"PASS __tests__/console.test.js + ✓ can mock console.error calls from jsdom + +" +`; + +exports[`the jsdom console is the same as the test console 3`] = ` +"Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites. +" +`; diff --git a/integration_tests/__tests__/console.test.js b/integration_tests/__tests__/console.test.js index 7207fb1fc463..61942d663a9f 100644 --- a/integration_tests/__tests__/console.test.js +++ b/integration_tests/__tests__/console.test.js @@ -54,3 +54,14 @@ test('does not print to console with --silent', () => { expect(rest).toMatchSnapshot(); expect(summary).toMatchSnapshot(); }); + +// issue: https://github.com/facebook/jest/issues/5223 +test('the jsdom console is the same as the test console', () => { + const {stderr, stdout, status} = runJest('console-jsdom'); + const {summary, rest} = extractSummary(stderr); + + expect(status).toBe(0); + expect(stdout).toMatchSnapshot(); + expect(rest).toMatchSnapshot(); + expect(summary).toMatchSnapshot(); +}); diff --git a/integration_tests/console-jsdom/__tests__/console.test.js b/integration_tests/console-jsdom/__tests__/console.test.js new file mode 100644 index 000000000000..c9c6d104ece7 --- /dev/null +++ b/integration_tests/console-jsdom/__tests__/console.test.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +/* eslint-env browser */ +'use strict'; + +beforeEach(() => { + jest.spyOn(console, 'error'); + console.error.mockImplementation(() => {}); +}); + +afterEach(() => { + console.error.mockRestore(); +}); + +test('can mock console.error calls from jsdom', () => { + // copied and modified for tests from: + // https://github.com/facebook/react/blob/46b3c3e4ae0d52565f7ed2344036a22016781ca0/packages/shared/invokeGuardedCallback.js#L62-L147 + const fakeNode = document.createElement('react'); + + const evt = document.createEvent('Event'); + const evtType = 'react-invokeguardedcallback'; + function callCallback() { + fakeNode.removeEventListener(evtType, callCallback, false); + throw new Error('this is an error in an event callback'); + } + + function onError(event) {} + + window.addEventListener('error', onError); + fakeNode.addEventListener(evtType, callCallback, false); + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + window.removeEventListener('error', onError); + + expect(console.error).toHaveBeenCalledTimes(1); +}); diff --git a/integration_tests/console-jsdom/package.json b/integration_tests/console-jsdom/package.json new file mode 100644 index 000000000000..0ded940b7cb7 --- /dev/null +++ b/integration_tests/console-jsdom/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "jsdom" + } +} diff --git a/packages/jest-environment-jsdom/src/index.js b/packages/jest-environment-jsdom/src/index.js index 4d6bada02876..6fa0c057eae7 100644 --- a/packages/jest-environment-jsdom/src/index.js +++ b/packages/jest-environment-jsdom/src/index.js @@ -8,12 +8,13 @@ import type {Script} from 'vm'; import type {ProjectConfig} from 'types/Config'; +import type {EnvironmentOptions} from 'types/Environment'; import type {Global} from 'types/Global'; import type {ModuleMocker} from 'jest-mock'; import {FakeTimers, installCommonGlobals} from 'jest-util'; import mock from 'jest-mock'; -import {JSDOM} from 'jsdom'; +import {JSDOM, VirtualConsole} from 'jsdom'; class JSDOMEnvironment { dom: ?Object; @@ -22,7 +23,7 @@ class JSDOMEnvironment { errorEventListener: ?Function; moduleMocker: ?ModuleMocker; - constructor(config: ProjectConfig) { + constructor(config: ProjectConfig, options: EnvironmentOptions = {}) { this.dom = new JSDOM( '', Object.assign( @@ -30,6 +31,9 @@ class JSDOMEnvironment { pretendToBeVisual: true, runScripts: 'dangerously', url: config.testURL, + virtualConsole: new VirtualConsole().sendTo( + options.console || console, + ), }, config.testEnvironmentOptions, ), diff --git a/packages/jest-runner/src/run_test.js b/packages/jest-runner/src/run_test.js index 9c54916c522a..4d27c5ab9689 100644 --- a/packages/jest-runner/src/run_test.js +++ b/packages/jest-runner/src/run_test.js @@ -74,11 +74,6 @@ async function runTestInternal( RuntimeClass, >); - const environment = new TestEnvironment(config); - const leakDetector = config.detectLeaks - ? new LeakDetector(environment) - : null; - const consoleOut = globalConfig.useStderr ? process.stderr : process.stdout; const consoleFormatter = (type, message) => getConsoleOutput( @@ -98,6 +93,11 @@ async function runTestInternal( testConsole = new BufferedConsole(); } + const environment = new TestEnvironment(config, {console: testConsole}); + const leakDetector = config.detectLeaks + ? new LeakDetector(environment) + : null; + const cacheFS = {[path]: testSource}; setGlobal(environment.global, 'console', testConsole); diff --git a/types/Environment.js b/types/Environment.js index 925150793cbc..ed6ee314c490 100644 --- a/types/Environment.js +++ b/types/Environment.js @@ -12,8 +12,12 @@ import type {Global} from './Global'; import type {Script} from 'vm'; import type {ModuleMocker} from 'jest-mock'; +export type EnvironmentOptions = { + console?: Object, +}; + declare class $JestEnvironment { - constructor(config: ProjectConfig): void; + constructor(config: ProjectConfig, options?: EnvironmentOptions): void; runScript(script: Script): any; global: Global; fakeTimers: {