Jest单元测试遇双重问题:window.open未实现+函数调用断言失败
问题概述
编写React组件及Jest单元测试后,出现两个问题:
- 断言显示
NavigateToOtherSite函数调用次数为0,不符合预期 - 控制台抛出
Error: Not implemented: window.open错误
相关代码如下:
Navigate.ts
const NavigateToOtherSite = (url: string) => { window.open(url, 'blank'); }; export default NavigateToOtherSite;
App.tsx
import * as React from 'react'; import './style.css'; import NavigateToOtherSite from './Navigate'; export default function App() { return ( <div data-test='id-1' onClick={() => NavigateToOtherSite('https://fast.com/')}> <h1>Hello StackBlitz!</h1> <p>Start editing to see some magic happen :)</p> </div> ); }
App.test.tsx
import React from 'react'; import { shallow } from 'enzyme'; import * as Navigate from './Navigate'; it('should open correct website', async () => { let test = jest .spyOn(Navigate, 'NavigateToOtherSite') .mockImplementation(); const wrapper = shallow(<App/>); wrapper.find('[data-test="id-1"]').simulate('click'); expect(test).toHaveBeenCalled(); });
失败详情
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
控制台错误:
console.error Error: Not implemented: window.open
解决方案
1. 修复NavigateToOtherSite未被调用的问题
核心原因是导入方式与Spy匹配不兼容:
- 组件中使用默认导入
import NavigateToOtherSite from './Navigate' - 测试中试图Spy命名导出
NavigateToOtherSite,但原文件仅导出默认函数,导致Spy未生效
方案一:修改测试的Spy逻辑
直接针对模块的default属性进行Spy:
import React from 'react'; import { shallow } from 'enzyme'; import App from './App'; it('should open correct website', () => { // Spy默认导出的函数 const navigateSpy = jest.spyOn(require('./Navigate'), 'default') .mockImplementation(() => {}); const wrapper = shallow(<App/>); wrapper.find('[data-test="id-1"]').simulate('click'); // 验证调用次数与参数 expect(navigateSpy).toHaveBeenCalledTimes(1); expect(navigateSpy).toHaveBeenCalledWith('https://fast.com/'); // 清理Spy navigateSpy.mockRestore(); });
方案二:改用命名导出
调整Navigate.ts为命名导出:
export const NavigateToOtherSite = (url: string) => { window.open(url, 'blank'); };
组件中同步修改导入方式:
import { NavigateToOtherSite } from './Navigate';
此时原测试中的Spy代码即可正常工作。
2. 解决window.open未实现错误
Jest的jsdom环境默认未实现window.open,可通过两种方式处理:
- 在测试中提前Mock该方法:
beforeAll(() => { window.open = jest.fn(); }); afterAll(() => { delete window.open; }); - 或者通过
mockImplementation替换原函数逻辑(如方案一的测试代码,已跳过原函数的window.open调用)
最终完整测试示例
import React from 'react'; import { shallow } from 'enzyme'; import App from './App'; beforeAll(() => { window.open = jest.fn(); }); afterAll(() => { delete window.open; }); it('should open correct website', () => { const navigateSpy = jest.spyOn(require('./Navigate'), 'default') .mockImplementation(() => {}); const wrapper = shallow(<App/>); wrapper.find('[data-test="id-1"]').simulate('click'); expect(navigateSpy).toHaveBeenCalledTimes(1); expect(navigateSpy).toHaveBeenCalledWith('https://fast.com/'); navigateSpy.mockRestore(); });
内容的提问来源于stack exchange,提问作者90CK
相关产品推荐
相关产品推荐

