You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的模块解析规则:

  1. 在项目根目录创建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',
  },
};
  1. 修改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"
          }
        }
      }
    }
  }
}
  1. 更新你的__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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:47:02