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

NgRX createEffect的catchError测试出现未处理Promise拒绝如何修复

NgRx Effects 测试报错修复方案

核心问题定位

你遇到的未处理Promise rejection报错由以下几个错误导致:

  • 测试依赖注入配置错误,没有为LoginService、SupabaseService提供mock实现,直接注入了真实服务实例
  • mock对象匹配错误:Effects中实际调用的是loginService.signIn,但测试里只mock了supabaseService.signIn,LoginService的真实逻辑执行时抛出的错误没有被Effects的catchError捕获
  • 测试断言逻辑不符合NgRx Effects的测试规范,没有用官方提供的expectObservable做流断言,手动subscribe的逻辑无法正确覆盖错误分支的返回结果

修复步骤

1. 修正TestBed依赖配置

首先在测试的beforeEach中注册两个服务的mock实现,避免调用真实服务逻辑:

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      provideMockActions(() => actions$),
      AuthEffects,
      // 注册mock服务替换真实实现
      { provide: LoginService, useValue: { signIn: jest.fn() } },
      { provide: SupabaseService, useValue: { signIn: jest.fn() } }
    ],
  });
  effects = TestBed.inject(AuthEffects);
  mockLoginService = TestBed.inject(LoginService);
  mockSupabaseService = TestBed.inject(SupabaseService);
});

2. 修正登录成功场景测试

直接mock Effects依赖的loginService.signIn方法返回成功结果,用expectObservable断言返回的Action符合预期:

it('should dispatch signInSuccess action when sign in succeeds', () => {
  const payload = { email: 'test@hotmail.com', password: '123', redirectTo: 'dashboard' };
  const triggerAction = AuthActions.signIn(payload);
  const expectedAction = AuthActions.signInSuccess();

  actions$ = cold('a', { a: triggerAction });
  jest.spyOn(mockLoginService, 'signIn').mockResolvedValue({});

  expect(effects.signIn$).toBeObservable(cold('b', { b: expectedAction }));
  expect(mockLoginService.signIn).toHaveBeenCalledWith(
    payload.email, 
    payload.password, 
    payload.redirectTo
  );
});

3. 修正登录失败场景测试

mockloginService.signIn返回错误结果,直接断言返回的signInErrorAction即可,不会再出现未捕获的Promise报错:

it('should dispatch signInError action when sign in fails', () => {
  const payload = { email: 'test@hotmail.com', password: '123', redirectTo: 'dashboard' };
  const mockError = new Error('test sign in failed');
  const triggerAction = AuthActions.signIn(payload);
  const expectedAction = AuthActions.signInError({ message: mockError.message });

  actions$ = cold('a', { a: triggerAction });
  jest.spyOn(mockLoginService, 'signIn').mockRejectedValue(mockError);

  expect(effects.signIn$).toBeObservable(cold('b', { b: expectedAction }));
  expect(mockLoginService.signIn).toHaveBeenCalledWith(
    payload.email, 
    payload.password, 
    payload.redirectTo
  );
});

额外说明

如果你的LoginService.signIn内部确实依赖SupabaseService.signIn,也可以选择mock Supabase的方法,但必须保证LoginService的实例是测试中注入的mock实例,避免跨服务调用逻辑不可控。直接mock Effects直接依赖的LoginService是更合理的单元测试实践,不需要耦合下层服务的实现逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 09:21:03