Angular(TypeScript)环境下用Jasmine模拟getCurrentPosition单元测试问题求解
现有写法的核心问题
- 模拟对象未挂载到全局navigator:你单独声明的
mockGeolocationspy对象没有替换浏览器全局的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
相关产品推荐
相关产品推荐

