Answer a question

I'm creating unit test for my Angular app but i don'k know create tests for my custom guard that use Redux.

This is my code of the guard

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']))
    );    
  }
}

I run npm run coverage

And this is the uncovered block (I need create unit test for canActivate, canLoad, and isAdmin

Uncovered block

And this is my unit testing file (default testing)

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

Answers

Thanks Wesley for your comment. Here's the solution

This is my code of guard

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']))
    );    
  }
}

And this is the test

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()
  })
});
Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐