我有一个导入组件的测试,该组件又导入一个使用window
对象的助手文件来提取查询字符串参数。我收到有关window
的以下错误:
FAIL src/js/components/__tests__/Controls.test.jsx
● Test suite failed to run
ReferenceError: window is not defined
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.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
我试图导入jsdom
import { JSDOM } from 'jsdom'
并在我的测试文件顶部实现提交的here解决方案:
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);
然而我仍然得到错误,似乎JSDOM的窗口对象没有接触到测试。
window
或document
之类的全局对象公开给jest测试? "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"
}
答案 0 :(得分:13)
您的问题依赖于配置。
在您设置的那一刻:
"testEnvironment": "jest-environment-node"
您正在将默认配置从类似浏览器的jest更改为jest-environment-node
(类似节点),这意味着您的测试将在NodeJs
环境下运行< / p>
要解决此问题,请将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
}
}
}
testEnvironment
[string]#默认:&#34; jsdom&#34;测试环境 将用于测试。 Jest中的默认环境是 通过jsdom的类似浏览器的环境。如果您正在构建节点 在service中,您可以使用node选项来使用类似节点的环境 代替。
正如我所看到的,您的测试应该在类似浏览器的环境中运行。
如果您需要显式节点环境,最好使用@jest-environment
隔离该情况:
/**
* @jest-environment node
*/
test('use node in this test file', () => {
expect(true).not.toBeNull();
});
如果你打算在node
环境下运行测试,那么或者相反
/**
* @jest-environment jsdom
*/
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
通过这种方法,您可以避免手动导入jsdom
并设置全局变量,jsdom
将自动模拟DOM
实现。
如果您需要更改测试环境,请使用符号@jest-environment
答案 1 :(得分:3)
您可以尝试
global.window = new jsdom.JSDOM().window;
global.document = window.document;
答案 2 :(得分:3)
您可以在此找到如何执行此操作的示例:
https://www.codementor.io/pkodmad/dom-testing-react-application-jest-k4ll4f8sd
例如:
import {jsdom} from 'jsdom';
const documentHTML = '<!doctype html><html><body><div id="root"></div></body></html>';
global.document = jsdom(documentHTML);
global.window = document.parentWindow;
答案 3 :(得分:1)
你可以简单地模仿location
:
global.location = {search: 'someSearchString'}
另请注意,测试中的global
是要测试的文件的全局上下文(global === window
)
请注意,只有在测试完成导入所有模块后模块进行window.location
调用时,此方法才有效。
export default () => window.location
因此,如果您的模块如下所示:
const l = window.location
export default l
它不起作用。在这种情况下,您可以使用jest.mock
模拟模块。
答案 4 :(得分:1)
https://github.com/facebook/jest/issues/2460#issuecomment-324630534
似乎有一个贡献者宣称他没有计划在开玩笑的环境下将jsdom暴露给全球。
但是,您可以使用Object.defineProperty(window, 'location', {value: '…'}
API来处理它,like the developer in Facebook do。在你的情况下,它可能像:
Object.defineProperty(window, 'location', {
value: {
search: ...
},
})
祝你好运!
答案 5 :(得分:1)
不确定,但我认为你可以用jest.fn()
global.window = jest.fn(() => {
location: { ... }
})
甚至可能是window = jest.fn(...)