如何使用Jest模拟JavaScript窗口对象?
我需要测试在浏览器中打开新选项卡的功能如何使用Jest模拟JavaScript窗口对象?,javascript,mocking,jestjs,Javascript,Mocking,Jestjs,我需要测试在浏览器中打开新选项卡的功能 openStatementsReport(contactIds) { window.open(`a_url_${contactIds}`); } 我想模拟窗口的open函数,以便验证是否将正确的URL传递给open函数 使用玩笑,我不知道如何模拟窗口。我试图设置窗口。用模拟函数打开,但这种方法不起作用。下面是测试用例 it('correct url is called', () => { window.open = jest.fn();
openStatementsReport(contactIds) {
window.open(`a_url_${contactIds}`);
}
我想模拟窗口的open
函数,以便验证是否将正确的URL传递给open
函数
使用玩笑,我不知道如何模拟窗口
。我试图设置窗口。用模拟函数打开,但这种方法不起作用。下面是测试用例
it('correct url is called', () => {
window.open = jest.fn();
statementService.openStatementsReport(111);
expect(window.open).toBeCalled();
});
但它给了我一个错误
expect(jest.fn())[.not].toBeCalled()
jest.fn()值必须是模拟函数或间谍。
收到:
函数:[函数匿名]
我应该如何处理测试用例?而不是窗口
使用全局
it('correct url is called', () => {
global.open = jest.fn();
statementService.openStatementsReport(111);
expect(global.open).toBeCalled();
});
你也可以试试
const open = jest.fn()
Object.defineProperty(window, 'open', open);
您可以尝试以下方法:
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();
});
我们还可以在setupTests
// setupTests.js
global.open = jest.fn()
并在实际测试中使用global
调用它:
// yourtest.test.js
it('correct url is called', () => {
statementService.openStatementsReport(111);
expect(global.open).toBeCalled();
});
在Jest配置中,添加setupfileafterenv:[“/setupTests.js”],创建该文件,并添加要在测试之前运行的代码:
// setupTests.js
window.crypto = {
.....
};
参考资料:以下方法对我有效。这种方法允许我测试一些应该在浏览器和Node.js中都能工作的代码,因为它允许我将window
设置为undefined
这是玩笑24.8(我相信):
如果类似于上的窗口位置问题,您可以尝试(调整):
有两种方法可以开玩笑地模仿globals:
使用mockImplementation
方法(最滑稽的方式),但它只适用于那些由jsdom
提供默认实现的变量<代码>窗口。打开
是其中之一:
test('it work',()=>{
//设置
const mockedOpen=jest.fn();
//如果不制作副本,将出现循环依赖性问题
常量originalWindow={…window};
const windowSpy=jest.spyOn(全局,“窗口”、“获取”);
windowSpy.mockImplementation(()=>({
…originalWindow,//以防需要其他窗口属性
打开:mockedOpen
}));
//测验
statementService.openStatementsReport(111)
expect(mockedOpen).toBeCalled();
//清理
windowSpy.mockRestore();
});
将该值直接指定给全局属性。这是最简单的,但它可能会触发某些window
变量的错误消息,例如window.href
test('it work',()=>{
//设置
const mockedOpen=jest.fn();
const originalOpen=window.open;
window.open=mockedOpen;
//测验
statementService.openStatementsReport(111)
expect(mockedOpen).toBeCalled();
//清理
window.open=originalOpen;
});
不要直接使用全局变量(需要一些重构)
与直接使用全局值不同,从另一个文件导入它可能更干净,因此使用Jest进行模拟将变得微不足道
文件./test.js
jest.mock('./fileWithGlobalValueExported.js');
从“/fileWithGlobalValueExported.js”导入{windowOpen};
从“/testedFile.js”导入{statementService};
//测验
测试('it works',()=>{
statementService.openStatementsReport(111)
expect(windowOpen).toBeCalled();
});
文件。/fileWithGlobalValueExported.js
export const windowOpen=window.open;
文件./testedFile.js
从“/fileWithGlobalValueExported.js”导入{windowOpen};
导出常量语句服务={
OpenStatementReport(联系人ID){
windowOpen(`a_url_${contactIds}`);
}
}
我找到了一个简单的方法:删除并替换
description('testcase',()=>{
const{open}=窗口;
以前(()=>{
//删除现有的
删除窗口。打开;
//替换为自定义值
window.open=jest.fn();
//也为“地点”工作,例如:
//window.location={origin:'http://localhost:3100' };
});
毕竟(()=>{
//还原原始
window.open=打开;
});
它('调用了正确的url',()=>{
openStatementsReport(111);
期待(窗口.打开).toBeCalled();//快乐,快乐
});
});
在我的组件中,我需要访问窗口.位置.搜索
。这就是我在玩笑测试中所做的:
Object.defineProperty(global, "window", {
value: {
location: {
search: "test"
}
}
});
如果不同测试中的窗口属性必须不同,我们可以将窗口模拟放入函数中,并使其可写,以便覆盖不同测试:
function mockWindow(search, pathname) {
Object.defineProperty(global, "window", {
value: {
location: {
search,
pathname
}
},
writable: true
});
}
并在每次测试后重置:
afterEach(() => {
delete global.window.location;
});
我直接将jest.fn()
分配给窗口。打开
window.open=jest.fn()
//…代码
期望(窗口打开)。已被调用时间(1)
预期(window.open).toHaveBeenCalledWith('/new tab','\u blank'))
可以测试它:
describe('TableItem Components', () => {
let open_url = ""
const { open } = window;
beforeAll(() => {
delete window.open;
window.open = (url) => { open_url = url };
});
afterAll(() => {
window.open = open;
});
test('string type', async () => {
wrapper.vm.openNewTab('http://example.com')
expect(open_url).toBe('http://example.com')
})
})
试过了,但对我不起作用。我的情况很奇怪,嘲弄在本地有效,但不适用于特拉维斯的公关合并。。。知道吗?@AlexJM你也有同样的问题吗?介意分享一下你是如何模拟窗口对象的吗?我只是在我的测试中定义了window.property@Andreas有没有办法将窗口模拟为未定义的谢谢!几个小时后,我只需要为全局更改窗口
,这比对象要好得多。定义属性
,因为这允许在模拟时不影响其他测试。这应该是可接受的答案,因为它模拟/间谍,而不是更改实际的全局属性。这是最好的方法!
afterEach(() => {
delete global.window.location;
});
describe('TableItem Components', () => {
let open_url = ""
const { open } = window;
beforeAll(() => {
delete window.open;
window.open = (url) => { open_url = url };
});
afterAll(() => {
window.open = open;
});
test('string type', async () => {
wrapper.vm.openNewTab('http://example.com')
expect(open_url).toBe('http://example.com')
})
})