如何将 Angular 6+ 服务变量注入 app-routing.module.spec.ts 并测试路由器重定向
How to inject Angular 6+ service variables into app-routing.module.spec.ts and test router redirection
我正在尝试测试如果 authenticated
变量设置为 true 是否成功重定向用户。
我尝试将我的 LoginService 注入 beforeEach
并将 authenticated
变量设置为 false。然后,在单元测试中,将该变量设置为 true。然后,我希望我的警卫发现 authenticated
设置为 true 的事实,然后重定向到仪表板页面。
应用程序路由-module.spec.ts:
import { LoginService } from './services/login.service';
import { Router } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';
import { Location } from "@angular/common";
import { routes } from "./app-routing.module";
import { AppComponent } from './components/app.component';
describe('AppRoutingModule, () => {
let location: Location;
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
providers: [LoginService]
})
router = TestBed.get(Router);
location = TestBed.get(Location);
fixture = TestBed.createComponent(AppComponent);
router.initialNavigation();
});
beforeEach(inject([LoginService], (loginService: LoginService) => {
loginService.authenticated = false;
}))
it('should redirect the user form the LoginComponent to the DashboardComponent if the user is already logged in', inject([LoginService](loginService: LoginService) => {
loginService.authenticated = true;
console.log(loginService);
router.navigate([""]).then(() => {
expect(location.path()).toBe("/dashboard");
});
}))
})
login.guard.ts:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { LoginService } from '../services/login.service';
import { Observable } from 'rxjs/index';
@Injectable({
providedIn: 'root'
})
export class LoginGuard implements CanActivate {
constructor(private router: Router, private loginService: LoginService) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
console.log('checked authenticated guard');
if (this.loginService.authenticated === true) {
this.loginService.navigationState.next(true);
return true;
} else {
this.router.navigate(['']);
return false;
}
}
}
login.service.ts:
public authenticated = false;
应用-routing.module.ts:
export const routes: Routes = [
{ path: '', component: LoginComponent },
{ path: 'dashboard', component: CurrentActivityComponent, canActivate: [LoginGuard] }
]
我希望测试通过,将用户重定向到 'dashboard',但它失败了:Expected '/' to be '/dashboard'.
我怀疑这与我注入服务的方式有关。但是我不确定我做错了什么。
在您的测试中,您正在导航到根本没有守卫的主要路线 (router.navigate([""])
)(换句话说,您的守卫没有被呼叫)。只有当您实际尝试访问受保护的路线时,才会调用守卫。因此,在您的测试中,您必须导航到仪表板 (router.navigate(['dashboard'])
) 才能通过。
要实现您所描述的重定向行为,您必须为此目的向第一条路线添加另一个守卫。
PS: Jasmine 还带有间谍,可以让你f.i。通过指定服务方法的 return 值,将组件测试与服务实现分离。不过,它们不适用于普通属性(没有 getter/setter)。如果你的服务有一个 isAuthenticated 方法,它看起来像这样:
const loginService = fixture.debugElement.injector.get(LoginService);
spyOn(loginService, 'isAuthenticated').and.returnValue(true);
间谍在每个 IT 块的范围内,这意味着它们对您的其他测试没有任何副作用。
我正在尝试测试如果 authenticated
变量设置为 true 是否成功重定向用户。
我尝试将我的 LoginService 注入 beforeEach
并将 authenticated
变量设置为 false。然后,在单元测试中,将该变量设置为 true。然后,我希望我的警卫发现 authenticated
设置为 true 的事实,然后重定向到仪表板页面。
应用程序路由-module.spec.ts:
import { LoginService } from './services/login.service';
import { Router } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';
import { Location } from "@angular/common";
import { routes } from "./app-routing.module";
import { AppComponent } from './components/app.component';
describe('AppRoutingModule, () => {
let location: Location;
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
providers: [LoginService]
})
router = TestBed.get(Router);
location = TestBed.get(Location);
fixture = TestBed.createComponent(AppComponent);
router.initialNavigation();
});
beforeEach(inject([LoginService], (loginService: LoginService) => {
loginService.authenticated = false;
}))
it('should redirect the user form the LoginComponent to the DashboardComponent if the user is already logged in', inject([LoginService](loginService: LoginService) => {
loginService.authenticated = true;
console.log(loginService);
router.navigate([""]).then(() => {
expect(location.path()).toBe("/dashboard");
});
}))
})
login.guard.ts:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { LoginService } from '../services/login.service';
import { Observable } from 'rxjs/index';
@Injectable({
providedIn: 'root'
})
export class LoginGuard implements CanActivate {
constructor(private router: Router, private loginService: LoginService) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
console.log('checked authenticated guard');
if (this.loginService.authenticated === true) {
this.loginService.navigationState.next(true);
return true;
} else {
this.router.navigate(['']);
return false;
}
}
}
login.service.ts:
public authenticated = false;
应用-routing.module.ts:
export const routes: Routes = [
{ path: '', component: LoginComponent },
{ path: 'dashboard', component: CurrentActivityComponent, canActivate: [LoginGuard] }
]
我希望测试通过,将用户重定向到 'dashboard',但它失败了:Expected '/' to be '/dashboard'.
我怀疑这与我注入服务的方式有关。但是我不确定我做错了什么。
在您的测试中,您正在导航到根本没有守卫的主要路线 (router.navigate([""])
)(换句话说,您的守卫没有被呼叫)。只有当您实际尝试访问受保护的路线时,才会调用守卫。因此,在您的测试中,您必须导航到仪表板 (router.navigate(['dashboard'])
) 才能通过。
要实现您所描述的重定向行为,您必须为此目的向第一条路线添加另一个守卫。
PS: Jasmine 还带有间谍,可以让你f.i。通过指定服务方法的 return 值,将组件测试与服务实现分离。不过,它们不适用于普通属性(没有 getter/setter)。如果你的服务有一个 isAuthenticated 方法,它看起来像这样:
const loginService = fixture.debugElement.injector.get(LoginService);
spyOn(loginService, 'isAuthenticated').and.returnValue(true);
间谍在每个 IT 块的范围内,这意味着它们对您的其他测试没有任何副作用。