Angular 17中Jest.mock()无法Mock Capacitor Device插件问题
Angular 17 Jest构建器Mock Capacitor Device插件失败的解决方法
问题分析
你的测试返回真实Web环境的设备信息,说明Jest没有正确加载你定义的Mock文件,而是直接使用了Capacitor的真实插件实现。核心原因可能是Angular 17实验性Jest构建器的默认配置未正确识别根目录的__mocks__目录,或者Mock的方式与插件的实际导出机制不匹配。
解决方案
方案1:直接在测试文件内Mock模块(最可靠)
跳过全局__mocks__目录,直接在测试文件中用Jest的工厂函数Mock整个@capacitor/device模块,确保Mock对象完全覆盖真实导出:
import { TestBed } from '@angular/core/testing'; import { DeviceInfoService } from './device-info.service'; import { Device } from '@capacitor/device'; // 用工厂函数直接Mock模块导出 jest.mock('@capacitor/device', () => ({ Device: { getInfo: jest.fn(), }, })); describe('DeviceInfoService', () => { let service: DeviceInfoService; const mockDeviceInfo = { model: 'iphone 15', osVersion: '15', operatingSystem: 'ios', manufacturer: 'apple', }; beforeEach(() => { TestBed.configureTestingModule({ providers: [DeviceInfoService], }); service = TestBed.inject(DeviceInfoService); // 每次测试前重置Mock状态 (Device.getInfo as jest.Mock).mockReset(); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should return mocked device info', async () => { // 给Mock方法指定返回值 (Device.getInfo as jest.Mock).mockResolvedValue(mockDeviceInfo); const result = await service.getInfo(); // 用toEqual比较对象内容(而非引用) expect(result).toEqual(mockDeviceInfo); // 验证方法被调用 expect(Device.getInfo).toHaveBeenCalledTimes(1); }); });
方案2:配置Jest识别全局__mocks__目录
如果想保留全局Mock文件,需要手动配置Jest的模块解析规则:
- 在项目根目录创建
jest.config.js:
module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], // 强制将@capacitor/device映射到你的Mock文件 moduleNameMapper: { '@capacitor/device': '<rootDir>/__mocks__/@capacitor/device.ts', }, };
- 修改
angular.json中Jest构建器的配置,指定使用自定义Jest配置:
{ "projects": { "your-project-name": { "architect": { "test": { "builder": "@angular-devkit/build-jest:jest", "options": { "jestConfig": "jest.config.js", "tsConfig": "tsconfig.spec.json" } } } } } }
- 更新你的
__mocks__/@capacitor/device.ts,让方法支持Jest Mock:
export const Device = { getInfo: jest.fn().mockResolvedValue({}), };
方案3:通过Angular依赖注入Mock(适用于Service依赖注入插件的场景)
如果你的DeviceInfoService是通过Angular的依赖注入获取Device插件(而非直接导入调用),需要在测试中提供Mock的依赖:
假设Service的实现是:
import { Injectable } from '@angular/core'; import { Device } from '@capacitor/device'; @Injectable({ providedIn: 'root' }) export class DeviceInfoService { constructor(private device: Device) {} async getInfo() { return this.device.getInfo(); } }
测试文件中需要这样配置:
import { TestBed } from '@angular/core/testing'; import { DeviceInfoService } from './device-info.service'; import { Device } from '@capacitor/device'; describe('DeviceInfoService', () => { let service: DeviceInfoService; let mockDevice: jest.Mocked<typeof Device>; const mockDeviceInfo = { model: 'iphone 15', osVersion: '15', operatingSystem: 'ios', manufacturer: 'apple', }; beforeEach(() => { mockDevice = { getInfo: jest.fn().mockResolvedValue(mockDeviceInfo), } as jest.Mocked<typeof Device>; TestBed.configureTestingModule({ providers: [ DeviceInfoService, { provide: Device, useValue: mockDevice }, ], }); service = TestBed.inject(DeviceInfoService); }); it('should return mocked device info', async () => { const result = await service.getInfo(); expect(result).toEqual(mockDeviceInfo); expect(mockDevice.getInfo).toHaveBeenCalled(); }); });
关键注意点
- 避免用
toBe比较对象:对象是引用类型,toBe检查引用是否相同,改用toEqual比较内容。 - 确保Mock方法的类型正确:用
jest.Mocked或类型断言将插件方法转为Jest Mock类型,避免类型错误。 - 每次测试后重置Mock:防止测试间的状态污染,确保结果可预测。
内容的提问来源于stack exchange,提问作者ebarooni
相关产品推荐
相关产品推荐

