Angular语言 - 如何用ActivatedRouteSnapshot RouterStateSnapshot和Globa



我正在为我的Angular应用创建单元测试,但我不知道为使用Redux的自定义守卫创建测试。

这是我的守卫代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
import { first, map, Observable, tap } from 'rxjs';
import { GlobalState } from '../state/app.reducer';
import { Store } from '@ngrx/store';
import { RolesAccount } from 'src/app/pages/auth/interfaces/auth.constant';

@Injectable({
providedIn: 'root'
})
export class AdministratorGuard implements CanActivate, CanLoad {

constructor(private route: Router,private store: Store<GlobalState>) {}

canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.isAdmin()
}
canLoad( route: Route, segments: UrlSegment[]): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.isAdmin()
}

isAdmin():Observable<true | UrlTree>{    
return this.store.select('authentication').pipe( 
first(), // take of first value
map(userStore => userStore.userLogged?.role || ''), 
//TODO we hardcode the email of administrator until role is in JWT
map(role => role === RolesAccount.ADMIN ? true : this.route.createUrlTree(['/home']))
);    
}
}

我运行npm run coverage

这是未覆盖的块(我需要为canActivate, canLoad, and isAdmin创建单元测试

)发现块

这是我的单元测试文件(默认测试)

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { AuthComponent } from 'src/app/pages/auth/auth.component';
import { IUserState } from 'src/app/pages/auth/interfaces/auth.interfaces';
import { AdministratorGuard } from '../administrator.guard';
fdescribe('AdministratorGuard', () => {
let guard: AdministratorGuard;
let store: MockStore<IUserState>;  
beforeEach(() => {
TestBed.configureTestingModule({
imports:[
RouterTestingModule.withRoutes(
[
{
path: 'auth',
component: AuthComponent
},
]
),
],
providers:[
provideMockStore({}),
]
});
guard = TestBed.inject(AdministratorGuard);
store = TestBed.inject(MockStore);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

Thanks in advance

根据您定义的方式,您需要在您定义的认证路径中添加保护。

RouterTestingModule.withRoutes(
[
{
path: 'auth',
canActivate: [AdministratorGuard],
component: AuthComponent
},
]),

然后在你的it中,你需要路由到你的"授权"路径来解雇那个守卫。

现在,我不喜欢这种方法,原因如下——你要测试RouterTestingModule的行为和真正的RouterModule一样。

相反,我建议把你的警备当作一项服务来测试。

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
AdministratorGuard,
provideMockStore({}),
]
});
guard = TestBed.inject(AdministratorGuard);
store = TestBed.inject(MockStore);
});
it('should allow canActivate', (done) => {
// ... setup to allow it to return true
guard.canActivate(null, null).subscribe(x => {
// code to make
expect(x).toBe(true);
done();
});
});
it('should deny canActivate', (done) => {
// ... setup to return false
guard.canActivate(null, null).subscribe(x => {
// code to make
expect(x).toBe(false);
done();
});
});

然后为canLoad添加其他测试以执行相同的操作。对于每个场景,您可能需要多个真假场景。您不会想要直接测试isAdmin函数,因为它不是此服务的公共接口。

感谢Wesley的评论。这就是解决方案

这是我的守卫代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
import { first, map, Observable, tap } from 'rxjs';
import { GlobalState } from '../state/app.reducer';
import { Store } from '@ngrx/store';
import { RolesAccount } from 'src/app/pages/auth/interfaces/auth.constant';
@Injectable({
providedIn: 'root'
})
export class AdministratorGuard implements CanActivate, CanLoad {
constructor(private route: Router,private store: Store<GlobalState>) {}
canActivate(): Observable<true | UrlTree> {
return this.isAdmin()
}
canLoad(): Observable<true | UrlTree>{
return this.isAdmin()
}
isAdmin():Observable<true | UrlTree>{    
return this.store.select('authentication').pipe( 
first(), // take of first value
map(userStore => userStore?.userLogged?.role || ''), 
//TODO we hardcode the email of administrator until role is in JWT
map(role => role === RolesAccount.ADMIN ? true : this.route.createUrlTree(['/home']))
);    
}
}

这是测试

import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { lastValueFrom, of } from 'rxjs';
import { AuthComponent } from 'src/app/pages/auth/auth.component';
import { RolesAccount } from 'src/app/pages/auth/interfaces/auth.constant';
import { IUserState } from 'src/app/pages/auth/interfaces/auth.interfaces';
import { AdministratorGuard } from '../administrator.guard';
describe('AdministratorGuard', () => {
let guard: AdministratorGuard;
let store: MockStore<IUserState>;  
let defaultState:IUserState = {
authentication:{
userLogged:{
name:'',
email:'',
phone:'',
accessToken:'',
refreshToken:'',
role: RolesAccount.USER
},  
}  
}
beforeEach(() => {
const routerStub = {
events: of('/'),
createUrlTree: (commands: any, navExtras = {}) => {}
};
TestBed.configureTestingModule({
imports:[
RouterTestingModule.withRoutes(
[
{
path: 'auth',
component: AuthComponent
},
]
),
],
providers:[
provideMockStore({
initialState:defaultState
}),
{ provide: Router, useValue: routerStub}        
]
});
guard = TestBed.inject(AdministratorGuard);
store = TestBed.inject(MockStore);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
it('can Activate to be True ', () => {
const storeSpy = spyOn(store, 'select').and.callThrough();
guard.canActivate()
expect(storeSpy).toHaveBeenCalledTimes(1);
});
it('can canLoad to be True ', () => {
const storeSpy = spyOn(store, 'select').and.callThrough();
guard.canLoad()
expect(storeSpy).toHaveBeenCalledTimes(1);
})
it('validate role ADMIN',async () => {
const nextState:IUserState = {  
authentication:{
userLogged:{
name:'Test',
email:'mailTest@gmail.com',
phone:'+5411557788',
accessToken:'asfksakmfaskmfsakm',
refreshToken:'safla25l4235lllfs',
role: RolesAccount.ADMIN
},    
}     
}
store.setState(nextState);
const isAdmin = await lastValueFrom(guard.isAdmin())
expect(isAdmin).toBeTrue()
})
it('if is not admin,navigate home',async () => {
const nextState:IUserState = {  
authentication:null
}
store.setState(nextState);
const isAdmin = await lastValueFrom(guard.isAdmin())
expect(isAdmin).toBeUndefined()
})
});

相关内容

  • 没有找到相关文章

最新更新