【问题标题】:How to test guards in Angular 7 ngrx 6.1如何在 Angular 7 ngrx 6.1 中测试守卫
【发布时间】:2018-11-29 11:45:49
【问题描述】:

我们使用 Angular 5 并将其更新为 7。 目前 store select 写入 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 重构单元测试吗?

【问题讨论】:

    标签: angular unit-testing redux karma-jasmine ngrx


    【解决方案1】:

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

    更新: 本来我以​​为你使用的是旧的 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,因此您需要根据需要使用 mergeMapswitchMap 等运算符。

    我不确定您在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%。我希望这至少可以帮助您找到正确的方向。

    【讨论】:

    • 我发现了这个question,这表明我在更改地图以选择时给出了错误的建议。我将编辑我的答案以反映这一点。同样在那篇文章中,它建议像这样导入选择:import { select } from '@ngrx/store';。你就是这样做的吗?
    猜你喜欢
    • 1970-01-01
    • 2019-05-13
    • 2017-11-11
    • 2020-01-25
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    相关资源
    最近更新 更多