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

Angular单元测试fixture.whenStable内断言报SPEC HAS NO EXPECTATIONS如何解决

问题原因

  • 断言放在fixture.whenStable().then()回调中时,测试用例的同步代码执行完毕时回调还未触发,Jasmine 检测不到任何expect执行,就会抛出SPEC HAS NO EXPECTATIONS提示,同时断言还没执行测试就已经结束。
  • 把断言直接放到外层时,组件的异步变更还未完成,DOM 状态没有更新,所以断言会失败。

解决方案

方案1:使用async/await语法

用JS原生async关键字修饰测试函数,await等待fixture.whenStable()执行完成后再运行断言,Jasmine 可以正常检测到所有断言逻辑:

it('当前在职员工的保存按钮和其余字段应为可编辑状态', async () => {
  let employee1 = new Employee();
  employee1.id = 1;
  employee1.name = "Vineel pellella";
  employee1.workLocation = "Hyderabad";
  employee1.email = "vineel.royal@gmail.com";
  employee1.contactNo = 9985896040;
  employee1.dateOfBirth = new Date().toDateString();
  employee1.dateOfJoining = new Date().toDateString();
  // 若组件判断禁用逻辑依赖在职状态字段,请补充赋值
  // employee1.isCurrentEmployed = true;

  component.emp = employee1;
  fixture.detectChanges();

  // 等待所有异步任务执行完成
  await fixture.whenStable();
  // 再次执行变更检测,确保DOM状态更新完毕
  fixture.detectChanges();

  expect(fixture.debugElement.nativeElement.querySelector("#empId").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#empName").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfBirth").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#designation").disabled).toBe(false);
  
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfJoining").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#workLocation").disabled).toBe(false);
  
  expect(fixture.debugElement.nativeElement.querySelector("#inputGroupSelect01").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#contactNumber").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#email").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfLeaving").disabled).toBeFalsy();
  expect(fixture.debugElement.nativeElement.querySelector("#save").disabled).toBeFalsy();
});

方案2:使用fakeAsync + tick组合

如果测试场景不存在HTTP请求、定时器这类异步宏任务,可以用Angular测试工具提供的fakeAsync包裹测试函数,调用tick()清空所有待执行的微任务后直接写断言即可:

import { fakeAsync, tick } from '@angular/core/testing';

it('当前在职员工的保存按钮和其余字段应为可编辑状态', fakeAsync(() => {
  let employee1 = new Employee();
  employee1.id = 1;
  employee1.name = "Vineel pellella";
  employee1.workLocation = "Hyderabad";
  employee1.email = "vineel.royal@gmail.com";
  employee1.contactNo = 9985896040;
  employee1.dateOfBirth = new Date().toDateString();
  employee1.dateOfJoining = new Date().toDateString();

  component.emp = employee1;
  fixture.detectChanges();
  // 执行所有待处理的微任务
  tick();
  fixture.detectChanges();

  expect(fixture.debugElement.nativeElement.querySelector("#empId").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#empName").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfBirth").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#designation").disabled).toBe(false);
  
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfJoining").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#workLocation").disabled).toBe(false);
  
  expect(fixture.debugElement.nativeElement.querySelector("#inputGroupSelect01").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#contactNumber").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#email").disabled).toBe(false);
  expect(fixture.debugElement.nativeElement.querySelector("#dateOfLeaving").disabled).toBeFalsy();
  expect(fixture.debugElement.nativeElement.querySelector("#save").disabled).toBeFalsy();
}));

注意事项

  • Angular v14及以上版本中,原来的async测试工具已经重命名为waitForAsync,避免和JS原生async关键字混淆,不建议再使用旧的async()写法。
  • 请确认Employee实例包含组件判断字段禁用逻辑依赖的在职状态字段,如果字段缺失或赋值错误,即便测试执行逻辑正确,断言也会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:18:00