如何使用 Jest 模拟 JavaScript 窗口对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41885841/
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
How to mock the JavaScript window object using Jest?
提问by danny
I need to test a function which opens a new tab in the browser
我需要测试一个在浏览器中打开一个新标签的功能
openStatementsReport(contactIds) {
window.open(`a_url_${contactIds}`);
}
I would like to mock the window's open function so I can verify the correct URL is passed in to the open function.
我想模拟窗口的 open 函数,以便我可以验证正确的 URL 是否被传递到 open 函数。
Using Jest, I don't know how to mock the window. I tried to set window.open with a mock function but this way doesn't work. Below is the test case
使用 Jest,我不知道如何模拟窗口。我试图用模拟函数设置 window.open 但这种方式不起作用。下面是测试用例
it('correct url is called', () => {
window.open = jest.fn();
statementService.openStatementsReport(111);
expect(window.open).toBeCalled();
});
but it gives me the error
但它给了我错误
expect(jest.fn())[.not].toBeCalled()
jest.fn() value must be a mock function or spy.
Received:
function: [Function anonymous]
what should I do to the test case? any suggestions or hints are appreciated
我应该对测试用例做什么?任何建议或提示表示赞赏
回答by Andreas K?berle
Instead of windowuse global
而不是window使用global
it('correct url is called', () => {
global.open = jest.fn();
statementService.openStatementsReport(111);
expect(global.open).toBeCalled();
});
you could also try
你也可以试试
const open = jest.fn()
Object.defineProperty(window, 'open', open);
回答by tvsbrent
A method that worked for me was the following. This approach allowed me to test some code that should work both in the browser and in Node, as it allowed me to set windowto undefined.
对我有用的方法如下。这种方法允许我测试一些应该在浏览器和 Node 中都可以运行的代码,因为它允许我window将undefined.
This was with Jest 24.8 (I believe):
这是 Jest 24.8(我相信):
let windowSpy;
beforeEach(() => {
windowSpy = jest.spyOn(global, 'window', 'get');
});
afterEach(() => {
windowSpy.mockRestore();
});
it('should return https://example.com', () => {
windowSpy.mockImplementation(() => ({
location: {
origin: 'https://example.com'
}
}));
expect(window.location.origin).toEqual('https://example.com');
});
it('should be undefined.', () => {
windowSpy.mockImplementation(() => undefined);
expect(window).toBeUndefined();
});
回答by Poh Zi How
We can also define it using globalin setupTests
我们也可以使用globalin定义它setupTests
// setupTests.js
global.open = jest.fn()
And call it using globalin the actual test:
并global在实际测试中调用它:
// yourtest.test.js
it('correct url is called', () => {
statementService.openStatementsReport(111);
expect(global.open).toBeCalled();
});
回答by abhishek khandait
You can try this:
你可以试试这个:
import * as _Window from "jsdom/lib/jsdom/browser/Window";
window.open = jest.fn().mockImplementationOnce(() => {
return new _Window({ parsingMode: "html" });
});
it("correct url is called", () => {
statementService.openStatementsReport(111);
expect(window.open).toHaveBeenCalled();
});
回答by serv-inc
If it's similar to the window location problem at https://github.com/facebook/jest/issues/890, you could try [adjusted]
如果它类似于https://github.com/facebook/jest/issues/890上的窗口位置问题,您可以尝试 [已调整]
delete global.window.open;
global.window = Object.create(window);
global.window.open = jest.fn();
回答by jmarceli
There are a couple of ways to mock globals in Jest:
在 Jest 中有两种模拟全局变量的方法:
- Use
mockImplementationapproach (most Jest like way), but it will work only for those variables which has some default implementation provided byjsdom,window.openis one of them:
- 使用
mockImplementation方法(最像 Jest 的方式),但它仅适用于那些具有由 提供的默认实现的变量jsdom,window.open是其中之一:
test('it works', () => {
// setup
const mockedOpen = jest.fn();
// without making a copy you will have a circular dependency problem
const originalWindow = { ...window };
const windowSpy = jest.spyOn(global, "window", "get");
windowSpy.mockImplementation(() => ({
...originalWindow, // in case you need other window properties to be in place
open: mockedOpen
}));
// tests
statementService.openStatementsReport(111)
expect(mockedOpen).toBeCalled();
// cleanup
windowSpy.mockRestore();
});
- Assign value directly to the global property, most straight forward but may trigger error messages for some
windowvariables e.g.window.href.
- 将值直接分配给全局属性,最直接,但可能会触发某些
window变量的错误消息,例如window.href.
test('it works', () => {
// setup
const mockedOpen = jest.fn();
const originalOpen = window.open;
window.open = mockedOpen;
// tests
statementService.openStatementsReport(111)
expect(mockedOpen).toBeCalled();
// cleanup
window.open = originalOpen;
});
- Don't use globals directly (requires a bit of refactoring)
- 不要直接使用全局变量(需要一些重构)
Instead of using the global value directly it might be cleaner to import it from another file, so mocking will became trivial with Jest.
不是直接使用全局值,而是从另一个文件导入它可能更干净,因此使用 Jest 进行模拟将变得微不足道。
./test.js
./test.js
jest.mock('./fileWithGlobalValueExported.js');
import { windowOpen } from './fileWithGlobalValueExported.js';
import { statementService } from './testedFile.js';
// tests
test('it works', () => {
statementService.openStatementsReport(111)
expect(windowOpen).toBeCalled();
});
./fileWithGlobalValueExported.js
./fileWithGlobalValueExported.js
export const windowOpen = window.open;
./testedFile.js
./testedFile.js
import { windowOpen } from './fileWithGlobalValueExported.js';
export const statementService = {
openStatementsReport(contactIds) {
windowOpen(`a_url_${contactIds}`);
}
}
回答by Jee Mok
I found an easy way to do it: delete and replace
我找到了一个简单的方法:删除和替换
describe('Test case', () => {
const { open } = window;
beforeAll(() => {
// Delete the existing
delete window.open;
// Replace with the custom value
window.open = jest.fn();
// Works for `location` too, eg:
// window.location = { origin: 'http://localhost:3100' };
});
afterAll(() => {
// Restore original
window.open = open;
});
it('correct url is called', () => {
statementService.openStatementsReport(111);
expect(window.open).toBeCalled(); // Happy happy, joy joy
});
});
回答by stefan
In your jest config add setupFilesAfterEnv: ["./setupTests.js"], create that file and add the code you want to run before the tests
在您的 jest 配置中添加 setupFilesAfterEnv: ["./setupTests.js"],创建该文件并添加您要在测试之前运行的代码
//setupTests.js
window.crypto = {
.....
};
Ref: https://jestjs.io/docs/en/configuration#setupfilesafterenv-array
参考:https: //jestjs.io/docs/en/configuration#setupfilesafterenv-array

