Angular 15中如何用Jest测试switchMap等RxJS操作符?
问题分析
你的测试虽然通过,但未覆盖tap、filter、take和switchMap的核心原因有三点:
- 你订阅的是原始的
refreshTokenSubject$,而非handleRefresh()返回的经过管道处理的Observable BehaviorSubject初始值为null,被filter((token) => token)直接过滤,导致后续操作符从未执行handleRefresh()方法缺少必要的参数(req和next),且你未订阅该方法返回的Observable
修正后的拦截器代码
首先修复handleRefresh的语法错误和参数缺失问题:
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null); private refreshTokenSubject$ = this.refreshTokenSubject.asObservable(); // 补充req和next参数,修正filter的语法错误 handleRefresh(req: HttpRequest<any>, next: HttpHandler) { return this.refreshTokenSubject$.pipe( tap(() => console.log('refresh token')), filter((token) => token), take(1), switchMap((token) => { return next.handle(this.addToken(req, token)); }) ); } // 假设addToken是添加token到请求的方法 private addToken(req: HttpRequest<any>, token: string): HttpRequest<any> { return req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); }
覆盖所有RxJS操作符的Jest测试
beforeEach(() => { interceptor = TestBed.inject(RefreshTokenInterceptor); requestMock = new HttpRequest("GET", "/fakeRequest"); }); it('should trigger tap, filter, take and switchMap operators correctly', () => { const mockToken = 'valid-refresh-token'; // 模拟addToken返回带token的请求 interceptor['addToken'] = jest.fn().mockReturnValue(requestMock); const next = { handle: jest.fn().mockReturnValue(of()) } as HttpHandler; // 监听console.log,验证tap执行 const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(); // 订阅handleRefresh返回的Observable const handleRefresh$ = interceptor['handleRefresh'](requestMock, next); const subscription = handleRefresh$.subscribe({ complete: () => { // 验证take(1)是否完成了Observable expect(subscription.closed).toBe(true); } }); // 先发送null,验证filter过滤无效token interceptor['refreshTokenSubject'].next(null); expect(next.handle).not.toHaveBeenCalled(); // 发送有效token,触发所有操作符 interceptor['refreshTokenSubject'].next(mockToken); // 验证各操作符的执行 expect(consoleLogSpy).toHaveBeenCalledWith('refresh token'); // tap执行 expect(interceptor['addToken']).toHaveBeenCalledWith(requestMock, mockToken); // switchMap中调用addToken expect(next.handle).toHaveBeenCalledWith(requestMock); // switchMap中调用next.handle expect(subscription.closed).toBe(true); // take(1)完成订阅 // 清理间谍和订阅 consoleLogSpy.mockRestore(); subscription.unsubscribe(); });
测试要点说明
- tap:通过监听
console.log验证其执行 - filter:先发送
null验证无效token被过滤,再发送有效token验证通过 - take(1):通过检查订阅是否关闭,验证Observable在一次有效发射后完成
- switchMap:验证
addToken和next.handle是否被正确调用
内容的提问来源于stack exchange,提问作者Leonardo Henrique
相关产品推荐
相关产品推荐

