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

Karma+Jasmine测试Angular路由navigate异步调用失败问题排查

Angular路由导航异步测试失败解决方案

问题背景

我正在开发一款Angular练习应用,使用Karma和Jasmine进行测试。测试路由navigate功能时,由于该调用位于then()回调中,异步特性导致测试失败,报错信息如下:

Expected spy navigate to have been called with:[ [ '/error' ] ] but it was never called。

业务代码

myFunction(): void {
  functionWhichReturnsPromise().then(() => {
    this.router.navigate('/error');
  });
}

测试代码

describe('myComponent', () => {
  let component: myComponent;
  let fixture: ComponentFixture<myComponent>;
  let router: Router;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      declarations: [myComponent],
      providers: [],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();

    fixture = TestBed.createComponent(myComponent);
    router = TestBed.inject(Router);
    component = fixture.componentInstance;
    spyOn('functionWhichReturnsPromise').and.returnValue(Promise.resolve());
    fixture.detectChanges();
  });

  it('should call navigate', () => {
    const spyRouter = spyOn(router, 'navigate').and.resolveTo(true);

    component.myFunction();

    expect(spyRouter).toHaveBeenCalledWith(['/error']);
  });
});

问题分析与解决步骤

1. 核心问题:未等待异步操作完成

测试中调用component.myFunction()后立刻执行断言,此时Promise的then()回调还未触发,navigate自然没有被调用,必须让测试等待异步流程完成。

2. 次要问题:Spy写法错误

原测试中spyOn('functionWhichReturnsPromise')的写法不符合Jasmine规范,spyOn需要指定对象和方法名。如果functionWhichReturnsPromise是组件的方法,要写成spyOn(component, 'functionWhichReturnsPromise');如果是服务或全局函数,需先注入对应实例再创建Spy。

修正后的测试代码(async/await版本)

describe('myComponent', () => {
  let component: myComponent;
  let fixture: ComponentFixture<myComponent>;
  let router: Router;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      declarations: [myComponent],
      providers: [],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();

    fixture = TestBed.createComponent(myComponent);
    router = TestBed.inject(Router);
    component = fixture.componentInstance;
    // 修正Spy写法:假设functionWhichReturnsPromise是组件的方法
    spyOn(component, 'functionWhichReturnsPromise').and.returnValue(Promise.resolve());
    fixture.detectChanges();
  });

  // 使用async/await等待Promise完成
  it('should call navigate', async () => {
    const spyRouter = spyOn(router, 'navigate').and.resolveTo(true);

    await component.myFunction(); // 等待异步流程结束

    expect(spyRouter).toHaveBeenCalledWith(['/error']);
  });
});

可选方案(fakeAsync + tick版本)

如果偏好Angular测试的fakeAsync语法,可以用tick()模拟时间流逝,触发Promise回调:

it('should call navigate', fakeAsync(() => {
  const spyRouter = spyOn(router, 'navigate').and.resolveTo(true);

  component.myFunction();
  tick(); // 推进时间,执行所有待处理的异步回调

  expect(spyRouter).toHaveBeenCalledWith(['/error']);
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:19:56