javascript `window` 没有暴露给 Jest
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46105596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
`window` is not being exposed to Jest
提问by 1252748
I have a test that imports a component that in turn imports a helper file that uses the windowobject to pull out a query string parameter. I get the following error about window:
我有一个测试导入一个组件,该组件又导入一个帮助文件,该文件使用该window对象提取查询字符串参数。我收到以下错误window:
FAIL src/js/components/__tests__/Controls.test.jsx
● Test suite failed to run
ReferenceError: window is not defined
Controls.jsx:
Controls.jsx:
import { Unwrapped as Controls } from '../Controls'
describe('<MyInterestsControls />', () => {
it('should render the component with the fixture data', () => {
const component = shallow(
<UnwrappedMyInterestControls
dashboardData={dashboardData}
loadingFlags={{ controls: false }}
/>
)
expect(component).toMatchSnapshot()
})
})
Controls.jsximports ./helpers/services.jswhich contains the following:
Controls.jsx导入./helpers/services.js,其中包含以下内容:
import * as queryString from 'query-string'
const flag = queryString.parse(window.location.search).flag || 'off'
^^^^^^ this seems to be the problem
I have attempted to import jsdom
我试图导入 jsdom
import { JSDOM } from 'jsdom'
And implement the solution presented hereat the top of my test file:
和落实提出的解决方案在这里,在我的测试文件的顶部:
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
const { window } = jsdom;
function copyProps(src, target) {
const props = Object.getOwnPropertyNames(src)
.filter(prop => typeof target[prop] === 'undefined')
.map(prop => Object.getOwnPropertyDescriptor(src, prop));
Object.defineProperties(target, props);
}
global.window = window;
global.document = window.document;
global.navigator = {
userAgent: 'node.js',
};
copyProps(window, global);
however I still get the error and it seems JSDOM's window object isn't exposed to the test.
但是我仍然收到错误消息,并且似乎 JSDOM 的窗口对象没有暴露在测试中。
How can I properly expose global objects like windowor documentto a jest test?
我怎样才能正确曝光像全局对象window或document一个玩笑测试?
相关的 package.json包.json "scripts": {
"test:watch": "NODE_ENV=test jest --watch"
},
...
"devDependencies": {
...
"jest": "^20.0.4",
"jest-mock": "^21.2.0",
"jsdom": "^11.0.0",
...
},
...
"jest": {
"verbose": true,
"collectCoverageFrom": [
"src/js/helpers/preparePayload.js",
"src/js/components-ni",
"!**/node_modules/**",
"!**/dist/**"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 50,
"functions": 50,
"lines": 75
}
},
"testEnvironment": "jest-environment-node"
}
回答by Jose Paredes
Your problem relies on the configuration.
您的问题取决于配置。
In the moment you set:
在您设置的那一刻:
"testEnvironment": "jest-environment-node"
you are changing the default configuration from jest which is browser-like to jest-environment-node(node-like)meaning that your test will be run under a NodeJsenvironment
您正在将默认配置从类似浏览器的 jest 更改为jest-environment-node(类似节点),这意味着您的测试将在NodeJs环境 下运行
To solve it either you set your testEnvironmentto jsdom
Or you remove the testEnvironmentfrom your config so it will take the default value in yourpackage.json:
要解决它,您可以将您设置testEnvironment为jsdom
或者您testEnvironment从您的配置中删除 ,以便它在您的配置中采用默认值package.json:
...
"jest": {
"verbose": true,
"collectCoverageFrom": [
"src/js/helpers/preparePayload.js",
"src/js/components-ni",
"!**/node_modules/**",
"!**/dist/**"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 50,
"functions": 50,
"lines": 75
}
}
}
This is what they say in the documentation:
这是他们在文档中所说的:
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. If you are building a node service, you can use the node option to use a node-like environment instead.
testEnvironment[string] # 默认值:"jsdom"将用于测试的测试环境。Jest 中的默认环境是通过 jsdom 的类似浏览器的环境。如果您正在构建节点服务,则可以使用节点选项来代替使用类似节点的环境。
Do you need the `node` environment?
你需要`node`环境吗?
As I could see, your tests are meant to be run under a browser-like environment.
正如我所看到的,您的测试旨在在类似浏览器的环境下运行。
If you ever need an explicit node environment, better you isolate that case using @jest-environment:
如果您需要一个明确的节点环境,最好使用@jest-environment以下方法隔离这种情况:
/**
* @jest-environment node
*/
test('use node in this test file', () => {
expect(true).not.toBeNull();
});
or the other way around if you are meant to run the tests under nodeenvironment
或者反过来,如果您打算在node环境下运行测试
/**
* @jest-environment jsdom
*/
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
Conclusion
结论
With this you can avoid importing jsdommanually and setting global variables, jsdomwill mock the DOMimplementation automatically.
有了这个,您可以避免jsdom手动导入和设置全局变量,jsdom将DOM自动模拟实现。
If you need to change the environment for your tests use the notation @jest-environment
如果您需要更改测试环境,请使用该符号 @jest-environment
回答by Demon
You could try doing
你可以尝试做
global.window = new jsdom.JSDOM().window;
global.document = window.document;
回答by fung
https://github.com/facebook/jest/issues/2460#issuecomment-324630534
https://github.com/facebook/jest/issues/2460#issuecomment-324630534
It seems like the one of the contributer declared that he is not planning expose jsdom to global under the jest environment.
似乎其中一位贡献者宣称他不打算在 jest 环境下将 jsdom 暴露给全局。
However, you could use Object.defineProperty(window, 'location', {value: '…'}API to approach it, like the developer in Facebook do. In your case it could be like:
但是,您可以使用Object.defineProperty(window, 'location', {value: '…'}API 来处理它,就像 Facebook 中的开发人员所做的那样。在你的情况下,它可能是这样的:
Object.defineProperty(window, 'location', {
value: {
search: ...
},
})
Good luck!
祝你好运!
回答by Javier Cobos
Here you can find examples of how to do this:
您可以在此处找到有关如何执行此操作的示例:
https://www.codementor.io/pkodmad/dom-testing-react-application-jest-k4ll4f8sd
https://www.codementor.io/pkodmad/dom-testing-react-application-jest-k4ll4f8sd
For example:
例如:
import {jsdom} from 'jsdom';
const documentHTML = '<!doctype html><html><body><div id="root"></div></body></html>';
global.document = jsdom(documentHTML);
global.window = document.parentWindow;
回答by Andreas K?berle
You can simply mock location:
你可以简单地模拟location:
global.location = {search: 'someSearchString'}
Also note, that globalin your test is the global context for the file to test (global === window)
另请注意,global在您的测试中是要测试的文件的全局上下文 ( global === window)
Note this will only work if your module make the window.locationcall after the test has been finishing import all the modules.
请注意,这仅在您的模块window.location在测试完成导入所有模块后进行调用时才有效。
export default () => window.location
So if your module looks like this:
因此,如果您的模块如下所示:
const l = window.location
export default l
it will not work. In this case you could mock the module using jest.mock.
不起作用。在这种情况下,您可以使用jest.mock.
回答by Mettin Parzinski
Not sure but i think you could do it with jest.fn()
不确定,但我认为你可以做到 jest.fn()
global.window = jest.fn(() => {
location: { ... }
})
maybe even as window = jest.fn(...)
也许甚至作为 window = jest.fn(...)

