angular - 如何在 Angular 7 ngrx 6.1 中测试守卫
问题描述
我们使用了 Angular 5 并将其更新为 7。目前在 pipe() 中存储选择写入;
一些单元测试失败:
export class MyGuard {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
this.store.dispatch(new Action());
return this.store.pipe(
select<IAppState>(getMainState),
map((state: IState) => {
this.router.navigate(['/', url]);
}),
catchError((a, b) => {
this.router.navigate(['/', 'error']);
return of(false);
}),
);
}
和单元测试:
it('should redirect to page ', inject(
[MyGuard, Service],
(guard: MyGuard, service: Service) => {
spyOn(service, 'method').and.callFake(b => of({ id: { status: 'ok'} }));
const route = new ActivatedRouteSnapshot();
route.params = { id: '2' };
const activation = guard.canActivate(route, {
root: null,
url: 'url',
});
if (activation instanceof Observable) {
activation.subscribe(activationValue => {
expect(activationValue).toBe(false);
expect(router.navigate).toHaveBeenCalled();
});
} else {
fail('should not happen - should return an observable with true');
}
},
));
我们会失败,因为激活 (guard.canActivate) 不是 Observable。一些帮助并告诉如何根据新的 ngrx 重构单元测试?
解决方案
您发布的内容似乎存在一些问题。
更新:最初我以为您使用的是旧的 rxjs 选择,但这是不正确的。请确保您正在使用来自 ngrx 的 select 和这样的导入:
import { select } from '@ngrx/store';
如果你需要canActivate()
返回一个 Observable,那么不要像这样声明它:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
而是像这样声明它:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
另一个有问题的部分是:
map((state: IState) => {
this.router.navigate(['/', url]);
}),
首先,它不返回任何东西,所以它破坏了可观察链 - 也许最简单的解决方法是简单地删除花括号,以便它从this.router.navigate()
. 但是 - 本节还有第二个问题:this.router.navigate
返回一个 promise,而不是 observable,所以如果你想在 observable 链中使用它,你需要用from
. 最后,由于这本身是一个 Observable 并返回一个 Observable,因此您需要使用诸如mergeMap
或 的运算符,switchMap
具体取决于您的需要。
我不确定您要在 中执行什么操作catchError
,所以我不理会它,但是您需要在出现错误时对其进行测试,以确保它按您预期的方式运行。
我还发现您当前的缩进很混乱。
最后,您没有发布有关this.store
您的特定实现的详细信息。确保它返回一个可观察的!:)
将所有这些放在一起,一个可能的重构可能如下所示:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
this.store.dispatch(new Action());
return this.store.pipe(
select<IAppState>(getMainState),
mergeMap((state: IState) =>
from(this.router.navigate(['/', url]))
),
catchError((a, b) => {
this.router.navigate(['/', 'error']);
return of(false);
}),
);
}
但是,由于我在上面详述的所有未知数,我对这将按原样工作的信心不足 50%。我希望这至少有助于为您指明寻找答案的正确方向。
推荐阅读
- google-apps-script - 通过 Google App Script 在 Google Sheet 上编辑多行时如何获得真实范围
- regex - 如何优化使用正则表达式和for循环编写的python代码?
- linux - Systemd 服务不会在启动时执行
- javascript - telegraf js中的时间触发器
- javascript - 在输入框中生成 0000 到 9999 的数字
- c - 冒泡排序功能后跳过for循环
- angular - 在 Angular Material 中使用 [style.width.%] 或 [ngStyle] 不会动态应用 Css 样式
- apache-kafka - kafka中partition比consumer少,如何优化那个consumer组的其他consumer
- python - 如何使用硒单击记事本菜单栏中的“文件”按钮?
- sql - 有没有办法在 Redshift Spectrum 中使用“IN”条件检查多个列?