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

Angular(TypeScript)环境下用Jasmine模拟getCurrentPosition单元测试问题求解

现有写法的核心问题
  • 模拟对象未挂载到全局navigator:你单独声明的mockGeolocation spy对象没有替换浏览器全局的navigator.geolocation,业务代码执行时调用的仍然是原生地理定位API,因此会触发真实的权限校验逻辑,抛出「用户拒绝定位」的报错。
  • API调用逻辑理解错误:navigator.geolocation.getCurrentPosition本身不是返回Promise的异步方法,而是通过传入的成功/失败回调函数传递结果。你在callFake中返回带then的对象完全不符合该API的调用逻辑,导致业务代码中包装的Promise永远无法resolve,触发超时。

你参考的旧方案中用arguments[0]本质就是调用第一个传入的成功回调,只需把入参显式声明即可完全避开arguments关键字,符合TypeScript严格模式要求。

正确实现代码
fit('should GEOLOCALIZE the BROWSER', async () => {
  const mockPosition = { coords: { latitude: 0, longitude: 0 } };
  // 直接在全局navigator.geolocation上创建spy,替换原生方法
  const geoSpy = spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake(
    // 显式声明入参,无需使用arguments
    (successCallback: PositionCallback) => {
      successCallback(mockPosition as Position);
    }
  );

  const result = await component.getCurrentPosition();
  // 校验调用参数符合业务代码配置
  expect(geoSpy).toHaveBeenCalledOnceWith(
    jasmine.any(Function), 
    jasmine.any(Function), 
    { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }
  );
  // 可额外校验返回的定位结果符合预期
  expect(result).toEqual(mockPosition);
});

如果需要模拟定位失败的场景,也可以调用第二个错误回调参数:

// 模拟用户拒绝定位的场景示例
spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake(
  (successCallback: PositionCallback, errorCallback: PositionErrorCallback) => {
    errorCallback(new PositionError(1, 'User denied Geolocation'));
  }
);

如果遇到TypeScript提示navigator.geolocation是只读属性无法挂载spy的情况,可以在测试前置钩子中通过Object.defineProperty覆盖全局属性:

beforeEach(() => {
  const mockGeo = jasmine.createSpyObj('Geolocation', ['getCurrentPosition']);
  Object.defineProperty(navigator, 'geolocation', {
    value: mockGeo,
    writable: true
  });
});

内容的提问来源于stack exchange,提问作者fergardi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 02:36:00