pinia状态持久化单元测试需用可控内存存储替代localstorage;通过传入mockstorage对象(含getitem/setitem方法)并验证其调用时机与参数,确保插件按预期读写,避免依赖真实api。

Pinia 状态持久化在单元测试中无法直接依赖真实 localStorage,因为 Jest、Vitest 等测试运行环境默认不提供完整 Web Storage API(尤其是 JSDOM 的实现有局限或行为不一致),且真实写入会污染测试上下文。要可靠验证持久化逻辑,关键不是“模拟 localStorage 本身”,而是**拦截插件的数据读写路径,用可控的内存对象替代存储介质**。
用自定义 storage 对象替换 localStorage
pinia-plugin-persistedstate(及 pinia-plugin-unistorage)都支持传入任意符合 StorageLike 接口的对象(即含 getItem、setItem、removeItem 方法)。测试时可创建一个简易内存存储:
- 定义一个干净的
mockStorage对象,内部用普通 JS 对象存键值对 - 在测试 setup 阶段,将该对象传给插件配置(如
storage: mockStorage)或通过strategies指定 - 每次测试后清空
mockStorage,确保隔离性
在 store 定义中显式接收 storage 配置
避免硬编码 localStorage,让 store 支持注入 storage 实例(便于测试替换):
- 修改 store 的
persist配置,使用函数式写法动态返回 storage - 例如:
storage: () => testStorage || localStorage,测试时传入testStorage - 或者把 storage 作为 defineStore 的 options 参数之一,在测试中传入 mock
验证持久化行为的测试要点
不测“能不能存进浏览器”,而测“插件是否按预期调用了写入/读取”:
- 初始化 store 后,检查
mockStorage.getItem是否被调用,且 key 正确(如"pinia/user") - 修改 state 字段(如
store.token = "abc")后,断言mockStorage.setItem被调用,且序列化后的值包含新 token - 手动设置
mockStorage初始值,再创建 store,验证 state 是否被正确还原(hydration) - 若用了
beforeHydrate或afterHydrate钩子,需单独 mock 并验证其执行时机和参数
注意插件版本与测试环境兼容性
部分旧版 pinia-plugin-persistedstate 在 JSDOM 中可能抛出 SecurityError(因未启用 storage),建议:
- Vitest 用户:在
vitest.config.ts中启用globals: true和environment: "jsdom",并确保 JSDOM 版本 ≥ 20 - Jest 用户:在
setupFilesAfterEnv中手动挂载global.localStorage(仅作兜底,仍推荐用自定义 storage 替代) - UniApp 测试:优先用
pinia-plugin-unistorage,它对uni.setStorageSync的 mock 更稳定,可直接 jest.mock('uni-app') 拦截










