如何在Jest中Mock使用$自动订阅语法的Svelte Stores?
问题核心原因
你当前的Mock写法将store导出项包装为了返回store实例的函数,而Svelte的$自动订阅语法要求绑定的对象本身是持有subscribe方法的store实例。组件编译后会直接调用导入的user对象的subscribe方法获取值,但你Mock的user是一个Jest模拟函数,本身没有subscribe方法,必须调用后才会返回符合契约的store实例,因此会触发取值为undefined的报错。
解决方案
1. 基础静态Mock(无需在测试中修改store值)
直接导出符合store契约的实例即可,不要额外套函数,注意导出的变量名要和原store文件的导出名完全对应:
import { writable } from 'svelte/store'; jest.mock('../../stores/users', () => ({ // 原store导出的变量名为user就写user,为currentUser就写currentUser user: writable({ isAdmin: true }) }));
2. 动态修改store值(适配多测试用例不同状态)
如果需要在不同测试用例中切换store状态,可以提前定义Mock的store实例,在测试逻辑中直接调用set/update方法修改值:
import { writable } from 'svelte/store'; // 提前定义Mock的store实例,注意要写在jest.mock代码之前 const mockUserStore = writable({ isAdmin: false }); jest.mock('../../stores/users', () => ({ user: mockUserStore })); test('普通用户不展示管理员标识', () => { mockUserStore.set({ isAdmin: false }); // 渲染组件、执行断言逻辑 }); test('管理员展示管理员标识', () => { mockUserStore.set({ isAdmin: true }); // 渲染组件、执行断言逻辑 });
注意:Jest执行时会将
jest.mock代码提升到文件顶部执行,不要把Mock的store实例定义在jest.mock的回调函数内部,否则会出现变量引用错误。如果使用Svelte Testing Library,修改store值后建议使用waitFor或find*系列查询等待响应式更新完成后再执行断言。
3. 通用Mock工具函数
如果需要Mock多个store,可以封装通用的工具函数简化逻辑:
import { writable } from 'svelte/store'; function createMockStore(initialValue) { const { subscribe, set, update } = writable(initialValue); return { subscribe, set, update, // 可选:添加重置方法快速恢复初始状态 reset: () => set(initialValue) }; } // 使用示例 const mockUserStore = createMockStore({ isAdmin: false }); jest.mock('../../stores/users', () => ({ user: mockUserStore }));
额外排查项
如果按照上述方案修改后仍报错,可先检查jest.mock中填写的store文件路径,是否和组件内import的相对路径完全匹配,路径不一致会导致Mock不生效。
内容的提问来源于stack exchange,提问作者Ben Shurts
相关产品推荐
相关产品推荐

