首页 > 解决方案 > 如何在 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 重构单元测试?

标签: angularunit-testingreduxkarma-jasminengrx

解决方案


您发布的内容似乎存在一些问题。

更新:最初我以为您使用的是旧的 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%。我希望这至少有助于为您指明寻找答案的正确方向。


推荐阅读