-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pass testConsole to TestEnvironment #5227
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it does. It's kinda big :) |
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"jest": { | ||
"testEnvironment": "jsdom" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,14 +23,17 @@ class JSDOMEnvironment { | |
errorEventListener: ?Function; | ||
moduleMocker: ?ModuleMocker; | ||
|
||
constructor(config: ProjectConfig) { | ||
constructor(config: ProjectConfig, options: EnvironmentOptions = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small nit: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Actually, I'm curious to know why it's necessary to add type information to the constructor. Isn't it already defined in types/Environment.js? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not so sure, but I guess it's for the ease of writing your own custom envs and updating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Happy to make a PR to add the |
||
this.dom = new JSDOM( | ||
'<!DOCTYPE html>', | ||
Object.assign( | ||
{ | ||
pretendToBeVisual: true, | ||
runScripts: 'dangerously', | ||
url: config.testURL, | ||
virtualConsole: new VirtualConsole().sendTo( | ||
options.console || console, | ||
), | ||
}, | ||
config.testEnvironmentOptions, | ||
), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying that this function doesn't work anymore in the latest version of jsdom? Can we just fix that instead (using Object.defineProperty?). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer using the offered API rather than trying to patch it. The way it's done here is a bit ad hoc though. Saying that all custom envs must attach console themselves is pretty breaking, so not sure about best way forward There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand how either of your comments relate to my question about the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mine is: "JSDOM has an API for setting the console, we should use it rather than just assigning to the global". Why it stopped working I don't know, though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SimenB but then it would only work for jsdom and every other environment will have to do something different. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll provide a link when I get to my computer. But I hoped my comment above would explain why the current solution wouldn't ever work... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, it's not a regression. It just never appeared before now. It happened now because of the changes in React. Look closer at my original issue and I explain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When JSDOM is initialized, if we don't provide our own implementation of VirtualConsole, then it uses one which references the global This is all happening outside the test environment, so using This is why we need to initialize JSDOM with our own instance of I hope that makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyway, I'm fine adding this as an additional parameter to the TestEnvironment constructor, but because of how JSDOM constructs a VirtualConsole with a reference to What would you prefer? |
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expect in the next major version we can make this a required argument, but thought it best to leave it as an optional argument for now. I default to an empty object in the jsdom environment. |
||
runScript(script: Script): any; | ||
global: Global; | ||
fakeTimers: { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved these to the
Features
section because whether this is a bug or a new feature is debatable, so it made more sense as a feature to me.