在 jest 中模拟 localstorage/sessionstorage 的关键是通过 setupfilesafterenv 阶段用 object.defineproperty 替换 window 上的实例,使用闭包封装可重置、带 storage 事件支持的内存对象,避免跨测试污染。

在 Jest 中模拟完整的浏览器存储行为(如 localStorage 和 sessionStorage),关键不是“覆盖全局对象”,而是**在测试环境初始化阶段,用可控、可重置的内存对象精准替代原生 API 的读写逻辑**。Jest 默认使用 JSDOM 环境,它已提供基础的 storage 实现,但默认不可靠(例如跨测试污染、不触发 storage 事件、无法拦截异常),因此需主动接管。
为什么不能直接赋值 global.localStorage?
直接在测试文件里写 global.localStorage = {...} 是无效的——JSDOM 在环境启动时已创建了 window.localStorage 实例,后续对 global 的赋值不会影响 window 下的对象引用。必须在 Jest 环境加载完成、测试运行前,通过 setupFilesAfterEnv 阶段劫持并替换 window 上的属性。
配置可重置、带事件支持的 localStorage Mock
在项目中新建 tests/jest-setup-storage.js:
// tests/jest-setup-storage.js
// 每个测试用例执行前自动重置,避免状态残留
const createStorageMock = () => {
let store = {};
return {
setItem(key, value) {
store[key] = String(value);
window.dispatchEvent(new StorageEvent('storage', { key, newValue: value }));
},
getItem(key) { return store[key] ?? null; },
removeItem(key) { delete store[key]; },
clear() { store = {}; },
key(index) { return Object.keys(store)[index] || null; },
get length() { return Object.keys(store).length; }
};
};
// 替换 window 上的实例(注意:必须在 window 已存在后操作)
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'localStorage', {
value: createStorageMock(),
writable: true,
configurable: true
});
Object.defineProperty(window, 'sessionStorage', {
value: createStorageMock(),
writable: true,
configurable: true
});
}
在 jest.config.js 中启用该 setup 文件
确保它被 Jest 正确加载:
// jest.config.js
module.exports = {
setupFilesAfterEnv: [
'
],
testEnvironment: 'jsdom'
};
验证与使用示例
在测试中可自由读写,并断言事件或状态:
// storage.test.js
test('localStorage 触发 storage 事件且数据可读', () => {
const handler = jest.fn();
window.addEventListener('storage', handler);
localStorage.setItem('theme', 'dark');
expect(localStorage.getItem('theme')).toBe('dark');
expect(handler).toHaveBeenCalledTimes(1);
expect(handler.mock.calls[0][0].key).toBe('theme');
localStorage.clear();
expect(localStorage.length).toBe(0);
});
这样配置后,每个测试用例都拥有独立、干净、事件完备的 storage 实例,无需手动清理,也不会相互干扰。核心在于:用 setupFilesAfterEnv 控制时机,用闭包封装私有 store,用 Object.defineProperty 强制替换,而非简单赋值。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











