Jest官方ES6 Class Mocks ESM示例运行报错:SoundPlayer.mockClear不是函数
报错触发原因
Jest的ESM模块Mock机制和CommonJS存在本质差异:
- ESM的导入属于静态只读引用,
jest.mock无法像CommonJS场景一样直接替换你导入的SoundPlayer变量指向的内容,你代码中导入的SoundPlayer实际还是原始的类定义,没有Jest模拟函数自带的mockClear等方法,调用时自然抛出类型错误。 - 你编写的
jest.mock工厂函数返回值不符合ESM导出规范,ESM的默认导出对应default字段,你直接返回模拟构造函数的写法在ESM模式下无法正确绑定到默认导出对象上。
修复方案
前置配置确认
先确保基础ESM支持配置正确:
- 项目
package.json中添加"type": "module"字段,声明模块为ESM格式 - Jest配置文件(如
jest.config.js)中添加配置项extensionsToTreatAsEsm: ['.js'],开启.js文件的ESM处理支持
测试代码修改
调整后的测试代码如下:
import {jest} from '@jest/globals'; // 命名空间导入整个模块 import * as SoundPlayerModule from './sound-player'; import SoundPlayerConsumer from './sound-player-consumer'; // 用jest.mocked包装默认导出,拿到带模拟方法的构造函数 const SoundPlayer = jest.mocked(SoundPlayerModule.default); const mockPlaySoundFile = jest.fn(); jest.mock('./sound-player', () => { // 适配ESM导出规范,明确返回default字段 return { default: jest.fn().mockImplementation(() => { return {playSoundFile: mockPlaySoundFile}; }) }; }); beforeEach(() => { SoundPlayer.mockClear(); mockPlaySoundFile.mockClear(); }); it('The consumer should be able to call new() on SoundPlayer', () => { const soundPlayerConsumer = new SoundPlayerConsumer(); expect(soundPlayerConsumer).toBeTruthy(); }); it('We can check if the consumer called the class constructor', () => { const soundPlayerConsumer = new SoundPlayerConsumer(); expect(SoundPlayer).toHaveBeenCalledTimes(1); }); it('We can check if the consumer called a method on the class instance', () => { const soundPlayerConsumer = new SoundPlayerConsumer(); const coolSoundFileName = 'song.mp3'; soundPlayerConsumer.playSomethingCool(); expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); });
修改说明
- 改用命名空间导入整个
sound-player模块,再通过jest.mocked包装默认导出,即可拿到带Jest模拟方法的构造函数实例 - 调整
jest.mock工厂函数返回结构,明确对应ESM默认导出的default字段,确保模拟构造函数可以正确替换原默认导出
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

