Jest 异步测试让我感到困惑
Jest Async tests are confusing me
场景如下:
使用 Jest/Spectator 测试 RXJS observable,但似乎无法到达我想通过当前设置测试的代码行
组件代码-
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 订阅块的那部分,在组件中,我看到它从未到达。
如何测试该行代码?
我想我明白你的问题了。
如果你有:
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);
}),
当你订阅那个 RxJS 流时,return of(..
会让它进入成功块而不是错误块,因为 catchError
是说如果有错误,就这样处理return 这个 (of(..
) 用于流。
我看到你在流的错误部分期待导航调用。
我会尝试将测试更改为:
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();
}
});
});
场景如下:
使用 Jest/Spectator 测试 RXJS observable,但似乎无法到达我想通过当前设置测试的代码行
组件代码-
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 订阅块的那部分,在组件中,我看到它从未到达。
如何测试该行代码?
我想我明白你的问题了。
如果你有:
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);
}),
当你订阅那个 RxJS 流时,return of(..
会让它进入成功块而不是错误块,因为 catchError
是说如果有错误,就这样处理return 这个 (of(..
) 用于流。
我看到你在流的错误部分期待导航调用。
我会尝试将测试更改为:
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();
}
});
});