0

这是场景:

使用 Jest/Spectator 测试可观察的 RXJS,但似乎无法通过当前设置进入我想要测试的代码行

组件代码 -

  ngOnInit(): void {  
    this.authDetail$ = this.validateToken(this.token).pipe(
      takeUntil(this.unsubscribe$),
      catchError((error) => { 
        if (error) {
          // I want to test this next line...
          // But I never see it run...
          this.router.navigate(['unauthorized'], { replaceUrl: true });
        }
        // This only exists to satisfy the observable chain.
        return of({} as SomeModel);
      }),
    );
  }

  validateToken(token: string): Observable<SomeModel> {
    return this.authService.lookupByToken(token);
  }

测试-

  it('should redirect to "unauthorized" when error is thrown', (done) => {

      jest.spyOn(spectator.component, 'validateToken')
        .mockReturnValue(throwError({ status: 403 }) as any);

      spectator.component.validateToken('invalid_token').subscribe({
        next: (data) => {
          console.log('NEXT BLOCK: Should Have Thrown Error');
          done();
        },
        error: (error) => {
          expect(spectator.router.navigate).toHaveBeenCalledWith(
            ['unauthorized'],
            { replaceUrl: true },
          );
          expect(error).toBeTruthy(); 
          done();
        },
      });

      // This fires off the ngOnInit :)
      spectator.setRouteParam('token', 'INVALID_TOKEN');
    });

我遇到的问题是,当测试运行时,我可以看到我收到了 403,但没有调用 router.navigate。如果我在组件中 console.log 订阅块的那一部分,我会看到它从未到达过。

我如何测试那行代码?

4

1 回答 1

1

我想我看到了你的问题。

如果你有:

catchError((error) => { 
        if (error) {
          // I want to test this next line...
          // But I never see it run...
          this.router.navigate(['unauthorized'], { replaceUrl: true });
        }
        // This only exists to satisfy the observable chain.
        return of({} as SomeModel);
      }),

return of(..您订阅该 RxJS 流时,它将使其进入成功块而不是错误块,因为catchError如果有错误,则以这种方式处理它并of(..为流返回 this ()。

我看到您在流的错误部分期待导航调用。

我会尝试将测试更改为:

it('should redirect to "unauthorized" when error is thrown', (done) => {

      jest.spyOn(spectator.component, 'validateToken')
        .mockReturnValue(throwError({ status: 403 }) as any);

      // This fires off the ngOnInit :)
      spectator.setRouteParam('token', 'INVALID_TOKEN');
      // subscribe to authDetail$ after it has been defined in ngOnInit
      spectator.component.authDetail$.pipe(take(1)).subscribe({
         next: (result) => {
           expect(spectator.router.navigate).toHaveBeenCalledWith(
            ['unauthorized'],
            { replaceUrl: true },
          );
          expect(result).toBeTruthy();
          done();
         }
      });
    });
于 2022-01-21T16:41:54.747 回答