Angular Karma测试router.navigate后重载页面报then未定义问题
报错原因
你碰到的Cannot read property of undefined (reading then )错误根源很明确:
- 通过
jasmine.createSpy创建的navigate方法间谍默认没有配置返回值,调用后会直接返回undefined - 业务代码里需要链式调用
navigate()返回值的.then()方法,对undefined读取then属性就会触发这个类型错误 - 你当前写的测试逻辑本身也有问题:手动调用spy对象的navigate方法完全不会走到你真实的业务代码里,等于没测目标逻辑。
正确单元测试编写方式
核心要做三件事:给Router的navigate方法配置符合预期的Promise返回值、拦截window.location.reload避免真的刷新页面、触发真实业务逻辑后校验两个行为是否符合预期。
完整示例代码如下:
import { Router } from '@angular/router'; import { fakeAsync, flush, TestBed } from '@angular/core/testing'; import { YourTargetComponent } from './your-target.component'; describe('路由跳转刷新逻辑测试', () => { let routerSpy: jasmine.SpyObj<Router>; let reloadSpy: jasmine.Spy; beforeEach(async () => { // 预置Router间谍,navigate方法返回成功状态的Promise routerSpy = jasmine.createSpyObj('Router', ['navigate']); routerSpy.navigate.and.resolveTo(true); // 关键配置,解决then方法不存在的问题 // 拦截reload方法,避免测试时触发真实页面刷新 reloadSpy = jasmine.createSpy('reload'); Object.defineProperty(window.location, 'reload', { configurable: true, value: reloadSpy }); await TestBed.configureTestingModule({ declarations: [YourTargetComponent], providers: [ { provide: Router, useValue: routerSpy } ] }).compileComponents(); }); it('跳转test路由成功后应当触发页面刷新', fakeAsync(() => { // 触发组件中包含目标逻辑的方法,比如你写在组件里的跳转方法 const fixture = TestBed.createComponent(YourTargetComponent); const component = fixture.componentInstance; component.triggerNavigation(); // 这个方法里包含this.router.navigate(['test']).then(...)的逻辑 // 清空微任务队列,等待Promise的then回调执行 flush(); // 校验路由跳转参数是否正确 expect(routerSpy.navigate).toHaveBeenCalledOnceWith(['test']); // 校验页面刷新逻辑是否被调用 expect(reloadSpy).toHaveBeenCalledTimes(1); })); });
几个注意点:
- 涉及Promise异步逻辑,优先用
fakeAsync配合flush()控制异步时序,避免断言执行时回调还没跑导致的测试误判 - 不要手动调用spy对象的方法,必须通过触发组件/服务自身的业务入口来执行代码,才能覆盖到真实的业务逻辑
- 配置window.location.reload的属性时记得加
configurable: true,方便后续其他用例需要时可以重新修改属性
内容的提问来源于stack exchange,提问作者Sowmiya C
相关产品推荐
相关产品推荐

