跨平台单元测试关键在于隔离环境依赖、抽象平台差异、按需适配执行层:通过接口封装平台能力(如storageadapter)、注入mock适配器、用jsdom模拟dom、vitest双环境运行、重置共享状态。

JavaScript 工具库的单元测试要真正跨平台(浏览器、Node.js、甚至 Deno 或 Web Worker 环境),关键不是“写一次跑 everywhere”,而是隔离环境依赖、抽象平台差异、按需适配执行层。下面从设计思路到具体实践分几步说清楚。
用标准化接口封装平台能力
避免在业务逻辑里直接调用 localStorage、fetch、process.env 等原生 API。改为定义清晰的接口,比如:
// storage.ts
export interface StorageAdapter {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}
// 默认适配器(Node.js)
export const nodeStorage: StorageAdapter = {
getItem: (key) => process.env[key] ?? null,
setItem: (key, value) => { process.env[key] = value; },
removeItem: (key) => { delete process.env[key]; }
};
// 浏览器适配器
export const browserStorage: StorageAdapter = {
getItem: (key) => localStorage.getItem(key),
setItem: (key, value) => localStorage.setItem(key, value),
removeItem: (key) => localStorage.removeItem(key)
};
测试时直接注入 mock 实现,无需条件判断运行环境:
- 单元测试中传入纯内存版
{ getItem: jest.fn(), ... } - 集成测试可切换
nodeStorage或browserStorage - 工具函数本身不感知平台,只依赖接口契约
用兼容性断言代替环境检测
不要写 if (typeof window !== 'undefined') { ... } 来分支逻辑——这会让测试路径爆炸。取而代之的是:
- 对输入/输出做行为断言,例如 “调用
parseUrl('https://a.b/c')应返回{ protocol: 'https:', host: 'a.b', path: '/c' }”,不关心底层用的是URL构造函数还是正则 - 若必须检测能力(如
structuredClone),把检测逻辑抽成独立函数并单独测试,主逻辑只接收检测结果作为参数 - 用 jsdom 在 Node.js 中模拟 DOM,让浏览器专属逻辑也能在 CI 中跑通
测试运行器选型与配置要点
推荐组合:Vitest + jsdom + 自定义环境别名,理由如下:
- Vitest 原生支持浏览器和 Node.js 模式,同一套测试文件可双端运行
- 通过
test.environment = 'jsdom'让 Node 端拥有window/document - 用
resolve.alias区分平台实现:{ '@mylib/storage': './adapters/storage.browser.ts' }(浏览器){ '@mylib/storage': './adapters/storage.node.ts' }(Node) - CI 中分别执行:
vitest run --environment node和vitest run --environment jsdom
处理全局副作用与状态污染
跨平台测试最易翻车的是共享状态(如修改 localStorage、重写 Date.now、挂载全局变量)。解决方式:
- 每个测试用例前用
beforeEach(() => { localStorage.clear(); })重置 - 用
vi.useFakeTimers()控制时间相关逻辑,避免setTimeout异步等待 - 对全局对象打补丁时,务必在
afterEach还原:const originalFetch = global.fetch; afterEach(() => { global.fetch = originalFetch; }) - 避免在
describe外部初始化单例或缓存,防止测试间污染
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











