如何在Jest中不修改源码Mock AudioContext解决jsdom不支持问题
Jest 环境下无侵入 mock AudioContext 方案
核心逻辑:jsdom 环境默认未挂载 AudioContext 全局属性,因此直接调用 spyOn 会因为属性为 undefined 报错。只需提前手动将 mock 的 AudioContext 构造函数挂载到全局,即可实现和 Math.random 一致的 mock 效果,全程无需修改业务源码。
单测试文件临时 mock
适合仅单个测试用例需要用到 AudioContext 的场景:
// 自定义mock AudioContext类,可根据业务需要补充方法实现 class MockAudioContext { constructor() {} // 示例:如果业务用到createOscillator方法,可在此处添加mock createOscillator = jest.fn(() => ({ connect: jest.fn(), start: jest.fn(), stop: jest.fn() })) } beforeEach(() => { // 挂载到全局,jsdom环境也可以替换为window,用globalThis可兼容不同环境 global.AudioContext = MockAudioContext // 兼容部分旧写法的webkit前缀实现 global.webkitAudioContext = MockAudioContext }) test('测试context为空时会新建AudioContext', () => { // 如果需要监听构造函数调用情况,可替换为jest.fn实现 const mockCtxConstructor = jest.fn(() => new MockAudioContext()) global.AudioContext = mockCtxConstructor // 此处调用你要测试的业务逻辑 const newState = yourTestFunction({ context: null }) expect(newState.context).not.toBeNull() expect(mockCtxConstructor).toHaveBeenCalledTimes(1) }) afterEach(() => { // 清理全局挂载,避免污染其他测试用例 delete global.AudioContext delete global.webkitAudioContext })
多测试文件全局 mock
如果多个测试用例都需要用到 AudioContext,可直接配置到 Jest 全局启动文件中:
- 首先在
jest.config.js中添加全局启动文件配置:
module.exports = { // 其余配置保持不变 setupFiles: ['./jest.setup.js'] }
- 在项目根目录新建
jest.setup.js,写入全局 mock 逻辑:
class MockAudioContext { // 在此处统一添加所有业务用到的AudioContext方法mock createGain = jest.fn(() => ({ connect: jest.fn(), gain: { value: 0, setValueAtTime: jest.fn() } })) decodeAudioData = jest.fn() resume = jest.fn().mockResolvedValue() suspend = jest.fn().mockResolvedValue() close = jest.fn().mockResolvedValue() } global.AudioContext = MockAudioContext global.webkitAudioContext = MockAudioContext
配置完成后所有测试文件都可以直接使用 mock 后的 AudioContext,无需重复定义。
如果你需要对 AudioContext 做方法监听、自定义返回值等操作,也可以在挂载后正常使用 spyOn:
// 注意必须先挂载属性才能调用spyOn global.AudioContext = jest.fn() const audioCtxSpy = jest.spyOn(global, 'AudioContext').mockReturnValue({ // 自定义返回的实例内容 })
内容的提问来源于stack exchange,提问作者glend
相关产品推荐
相关产品推荐

