用于单元测试 Angular Router 和 CanActivate 防护的最小模拟

c69*_*c69 -1 unit-testing angular angular-router-guards angular-router

import {Router, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree} from '@angular/router';

@Injectable({provideIn: 'root'})
export class FooGuard implements CanActivate {
  constructor (private readonly router: Router) {}

  canActivate (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<UrlTree> {
    const xxx = myMagic(next); // irrelevant app logic that depends on next url only

    return (async () => this.router.parseUrl(xxx));
  }
}
Run Code Online (Sandbox Code Playgroud)

试图找到一个没有一页额外样板的测试代码示例。希望每个模拟可以有接近 5-6 行代码。需要:

  • 模拟Router
  • 模拟ActivatedSnapshot

Val*_*kov 5

看一下RouterTestingModule。这不是一个六行代码的解决方案,而是一个非常紧凑的解决方案。我认为这是测试守卫和路线的最佳方法:

import { Component, Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';

@Injectable({
    providedIn: 'root'
})
export class FooGuard implements CanActivate {
    constructor (private readonly router: Router) {}

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree {
      const url = "some/new/url"; // create an url based on next snapshot
      return this.router.parseUrl(url);
    }
  }

@Component({ template: '' })
export class DummyComponent {}

function setup(): {
    router: Router
} {
    TestBed.configureTestingModule({
        imports: [
            RouterTestingModule.withRoutes([
                { path: 'test', component: DummyComponent, canActivate: [ FooGuard ] },
                { path: 'some/new/url', component: DummyComponent }
            ])
        ],
        declarations: [
            DummyComponent
        ]
    });

    return {
        router: TestBed.get(Router)
    };
}

describe(FooGuard.name, () => {
    it('should redirect to a new url', async () => {
        const { router } = setup();
        await router.navigateByUrl('/test');
        expect(router.url).toBe('/some/new/url');
    })
});

Run Code Online (Sandbox Code Playgroud)

实际上,常规方法Router.forRoot()也应该适用于这种情况,但RouterTestingModule必须更适合测试。例如,最后一个提供自定义 Location实现。