Vue组件单元测试:模拟window对象引发_history读取null错误
Vue Router单元测试控制台报错处理
场景说明
我有一个Vue组件,包含如下待单元测试的方法:
const close = () => { (window.open('', '_self').opener=window).close() }
我的测试代码如下:
import { createRouter, createWebHistory } from "vue-router"; describe('test suite', async () => { let router let wrapper beforeEach(async () => { router = createRouter({ history: createWebHistory(), routes: routes }) wrapper = mount(MyComponent, { global: { plugins: [router] } }) }) test('window.close is called when btn is clicked', async () => { const windowSpy = vi.spyOn(window, 'open').mockReturnValue({ close: vi.fn() }) const btn = wrapper.find('[name="BTN_1"]') await btn.trigger('click') expect(windowSpy).toHaveBeenCalledOnce() }) })
测试成功通过,但控制台输出如下错误信息:
[Vue Router warn]: Unexpected error when starting the router: TypeError: Cannot read properties of null (reading '_history') at Window.get history [as history]
报错原因及解决方案
这个报错是因为单元测试环境(比如Vitest/Jest)是模拟的浏览器环境,没有真实的window.history对象,而createWebHistory()依赖该对象,导致初始化路由时出错。
方案一:改用内存历史(推荐)
使用createMemoryHistory()替代createWebHistory(),内存历史不依赖真实浏览器环境,完全适配单元测试场景:
import { createRouter, createMemoryHistory } from "vue-router"; beforeEach(async () => { router = createRouter({ history: createMemoryHistory(), // 替换为内存历史模式 routes: routes }) wrapper = mount(MyComponent, { global: { plugins: [router] } }) })
方案二:手动模拟window.history
如果必须使用createWebHistory(),可以在测试前手动模拟window.history对象的必要属性:
beforeEach(async () => { // 模拟window.history的核心属性 Object.defineProperty(window, 'history', { value: { _history: {}, pushState: vi.fn(), replaceState: vi.fn() }, writable: true }) router = createRouter({ history: createWebHistory(), routes: routes }) wrapper = mount(MyComponent, { global: { plugins: [router] } }) })
优先选择方案一,内存历史模式能更好地隔离测试环境,避免不必要的浏览器API依赖。
内容的提问来源于stack exchange,提问作者demiglace
相关产品推荐
相关产品推荐

