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

Jasmine测试async方法报Cannot read properties of undefined (reading 'then')错误

报错原因
  • api.send方法的mock返回值不符合预期,甚至未被正确mock:
    1. 若api.send本身设计为返回Promise,你在测试中返回的Promise.resolve(of('pillars'))结构完全不匹配业务逻辑需要的格式:业务代码的then回调中需要读取返回结果的data属性,但你返回的Promise resolve后是RxJS的Observable对象,无对应属性,且如果send实际返回值为undefined时,调用.then()就会直接抛出"Cannot read properties of undefined (reading 'then')"报错。
    2. 若api.send本身设计为返回RxJS Observable,Observable本身不存在then方法,直接调用.then()也会触发该报错。
  • 异步测试未正确处理异步逻辑:getPillars是async异步方法,测试中直接调用后没有等待异步任务执行完成,Jasmine在测试用例执行结束后的jasmine.onComplete阶段捕获到未处理的Promise rejection。
  • 测试依赖注入不匹配:如果测试模块中没有正确将组件依赖的apiService替换为你做了spy的实例,组件实际调用的api.send没有被mock,默认返回undefined也会触发该报错。
  • 额外逻辑隐患:业务代码混用await和.then()写法,可读性差且容易出现逻辑问题。

修复方案

1. 业务代码优化(可选但推荐)

移除await和.then()混用的写法,简化逻辑:

getPillars = async (): Promise<void> => {
  if (localStorage.getItem('pillars')) {
    this.pillars = JSON.parse(localStorage.getItem('pillars'));
    return;
  }
  // 如果api.send返回Promise
  const res = await this.api.send('Categories', 'get', filter ? { filter: filter } : {});
  // 如果api.send返回Observable,需要先转Promise:
  // const res = await firstValueFrom(this.api.send('Categories', 'get', filter ? { filter: filter } : {}));
  const items = res.data.map(el => ({ id: el.id, name: el.name, type: 'Categories' }));
  localStorage.setItem('pillars', JSON.stringify(items));
  this.pillars = items;
}

2. 单元测试修复

  • 调整spy返回值为符合业务预期的结构
  • 测试用例改为async,调用异步方法时加await等待执行完成
  • 提前清空localStorage避免命中缓存分支,不走api.send逻辑
describe('getPillars()', () => {
  it('Should validate the session success', async () => {
    localStorage.removeItem('pillars');
    // 如果api.send返回Promise,spy返回对应结构的Promise
    const spy1 = spyOn(apiService, 'send').and.returnValue(Promise.resolve({
      data: [{id: 1, name: '测试分类'}],
      count: 1
    }));
    // 如果api.send返回Observable,spy直接返回对应结构的Observable
    // const spy1 = spyOn(apiService, 'send').and.returnValue(of({
    //   data: [{id: 1, name: '测试分类'}],
    //   count: 1
    // }));

    await component.getPillars();

    expect(spy1).toHaveBeenCalled();
  });
});

同时需要确认测试模块中已经正确提供了apiService依赖,保证你spy的实例就是组件实际注入的实例。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:36:01