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
相关产品推荐
相关产品推荐

