NGXS的Actions Observable做Jest测试时断言失败超时无报错问题
问题原因
这个问题不是NGXS的已知缺陷,是RxJS Observable的默认行为导致的:当Observable的next回调中抛出未捕获的异常时,异常会被Observable内部捕获并进入错误处理通道,既不会向上抛到测试运行器的全局上下文,也不会继续执行回调中后续的done()调用。测试框架既收不到断言失败的信号,也等不到测试结束的回调通知,最终就会触发超时。
你之前用Subject做对照测试表现正常,大概率是因为你的测试用例中没有给Subject的订阅配置错误回调,异常会被RxJS抛到全局的未处理错误事件,被测试框架捕获到了。
解决方案
方案1:补充订阅的错误回调
给subscribe方法传入完整的观察者对象,在错误回调中把异常传递给done,测试框架就能正常捕获到断言失败:
it('should example', (done) => { actions$ .pipe(ofActionCompleted(ExampleAction)) .subscribe({ next: () => { console.log('i was here! Before'); expect(true).toBeFalsy(); console.log('i was here! After'); done(); }, error: (err) => done(err) // 捕获回调内的所有异常,传递给测试框架 }); store.dispatch(new ExampleAction()); });
方案2:改用async/await写法(更推荐)
把Observable转成Promise,用async/await的同步写法编写测试,不需要手动处理done回调和错误捕获,断言抛出的异常会自动被测试框架识别。如果使用RxJS 6版本可以直接调用toPromise()方法,RxJS 7+可以用firstValueFrom:
import { take } from 'rxjs'; // 省略测试套件其他代码 it('should example', async () => { const actionCompletePromise = actions$.pipe(ofActionCompleted(ExampleAction), take(1)).toPromise(); store.dispatch(new ExampleAction()); await actionCompletePromise; // 直接写断言即可,失败会自动抛出 expect(true).toBeFalsy(); });
方案3:直接监听dispatch返回的Observable
NGXS的store.dispatch方法本身就会返回一个Action执行完成后触发的Observable,不需要额外监听全局的Actions流,写法更简洁:
it('should example', async () => { await store.dispatch(new ExampleAction()).toPromise(); expect(true).toBeFalsy(); });
内容的提问来源于stack exchange,提问作者N33D
相关产品推荐
相关产品推荐

