Vitest测试报错:window.URL.createObjectURL非函数,Mock无效求解答
问题分析与解决方案
核心原因排查
你遇到的问题本质是mock未在依赖模块访问window.URL前生效,或者mock的URL对象结构不符合库的预期,以下是具体原因和对应解决办法:
1. Mock时机晚于模块加载
azure-maps-control模块可能在你的mock代码执行前就已经被导入并读取了window.URL,导致后续的mock无法覆盖它的引用。
解决办法:
把mock代码放在测试文件的最顶部,在所有组件和依赖导入之前执行:
import { vi } from 'vitest'; // 先完成mock vi.stubGlobal('URL', { createObjectURL: vi.fn(() => 'mock-blob-url'), revokeObjectURL: vi.fn(), constructor: function URL() {}, // 保留构造函数避免库报错 toString: () => 'URL', }); // 再导入组件和测试工具 import { renderWithGlobalContext } from './your-test-utils-path'; import ClientPortifolio from './ClientPortifolio'; describe('ClinetPortfolio component', () => { it('should render ClinetPortfolio', () => { const el = renderWithGlobalContext(<ClientPortifolio />, { providerProps: { value: { state: {} } }, route: '/', }); expect(true).toBeFalsy(); }); });
2. 模块缓存导致mock不生效
如果之前的测试用例已经加载过azure-maps-control,Node.js的模块缓存会复用已加载的模块实例,此时新的mock不会对它生效。
解决办法:
在测试前重置模块缓存,并重新导入组件:
import { vi } from 'vitest'; describe('ClinetPortfolio component', () => { let ClientPortifolio; beforeAll(async () => { vi.resetModules(); // 清空模块缓存 vi.stubGlobal('URL', { createObjectURL: vi.fn(), revokeObjectURL: vi.fn(), constructor: function URL() {}, }); // 重新导入组件 ClientPortifolio = (await import('./ClientPortifolio')).default; }); it('should render ClinetPortfolio', () => { const el = renderWithGlobalContext(<ClientPortifolio />, { providerProps: { value: { state: {} } }, route: '/', }); expect(true).toBeFalsy(); }); });
3. URL对象mock不完整
部分库会依赖URL构造函数或其他原生属性,仅mockcreateObjectURL和revokeObjectURL可能导致库判定URL对象无效。
解决办法:
基于原生URL对象进行局部mock(如果测试环境存在原生URL):
beforeAll(() => { // 保留原生URL的其他属性,仅mock目标方法 vi.spyOn(window.URL, 'createObjectURL').mockReturnValue('mock-url'); vi.spyOn(window.URL, 'revokeObjectURL').mockImplementation(() => {}); });
如果测试环境中没有原生URL对象,先创建基础结构再mock:
beforeAll(() => { if (!window.URL) { window.URL = {}; } window.URL.createObjectURL = vi.fn(() => 'mock-url'); window.URL.revokeObjectURL = vi.fn(); // 补充库可能用到的其他属性 window.URL.toString = () => 'URL'; });
4. 测试上下文隔离导致mock失效
如果renderWithGlobalContext工具函数创建了独立的JSDOM上下文,全局的windowmock不会同步到这个隔离的上下文中。
解决办法:
修改工具函数,支持传入自定义window对象,或者在上下文创建后再执行mock:
it('should render ClinetPortfolio', () => { // 构造带mock的window对象 const mockWindow = { ...globalThis.window, URL: { createObjectURL: vi.fn(), revokeObjectURL: vi.fn(), }, }; // 假设工具函数支持传入window参数 const el = renderWithGlobalContext(<ClientPortifolio />, { providerProps: { value: { state: {} } }, route: '/', window: mockWindow, }); expect(true).toBeFalsy(); });
快速验证方法
在测试中添加打印语句,确认mock是否成功覆盖window.URL:
beforeAll(() => { vi.stubGlobal('URL', { createObjectURL: vi.fn(), revokeObjectURL: vi.fn(), }); console.log('Current window.URL:', window.URL); // 检查输出是否为mock对象 });
内容的提问来源于stack exchange,提问作者Renato N_
相关产品推荐
相关产品推荐

