简体   繁体   中英

How to write a unit test for angular routing with canActivate guard

How to write a unit test for angular routing with canActivate guard? I'm getting below error if I use canActivate guard on the routes. If not it is not throwing any error and passing the test. Please help me with a suitable example and also with an explanation.

app-routing.module.ts

export const routes: Routes = [
 { path: '', component: LoginComponent },
 { path: 'home', canActivate: [AuthGuard], component: HomeComponent },
 { path: '**', redirectTo: '/home' }
]

auth-guard.guard.ts

export class AuthGuard implements CanActivate {
  private auth: IAuth;

  constructor(
    private storageService: StorageService,
    private router: Router
  ){}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      this.auth = JSON.parse(this.storageService.getLocalStorageItem('auth'));
      if(this.auth){
        return true;
      }

      this.router.navigate(['/'], {queryParams: {returnUrl: state.url}});
      return false;
  }
  
}

app-routing.module.test.ts

test(`Navigate to 'home' takes you to /home`, fakeAsync(() => {
        router.navigate(['/home']).then(() => {
            expect(location.path()).toEqual('/home');
        });
        flush();
    }));

Test Result

Testing Router › Navigate to 'home' takes you to /home

    Uncaught (in promise): Error: expect(received).toEqual(expected) // deep equality

    Expected: "/home"
    Received: "/"
    Error: expect(received).toEqual(expected) // deep equality

You should pass true for AuthGuard.canActivate before you run the test. This is a Jasmine example (make the adjustments):

describe('Test Description', () => {
    ...
    beforeEach(() => {
       const canActivateStub = () => ({ canActivate: () => true });
       ... all your imports
       TestBed.configureTestingModule({
           ... (all your imports)
           providers: [
               { provide: AuthGuard, useValue: canActivateStub}
           ]
       })
    })
    ...
})

For AuthGuard test unit you can do:

  describe('AuthGuard', () => {
        let service: AuthGuard;
    
    
        it('can load instance', () => {
            const routerStubInit = () => ({ navigate: (array, object) => ({}) });
            TestBed.configureTestingModule({
                providers: [
                    AuthGuard,
                    HttpClient,
                    HttpHandler,
                    { provide: Router, useFactory: routerStubInit },
                ]
            });
            service = TestBed.inject(AuthGuard);
    
            expect(service).toBeTruthy();
        });
    
        describe('canActivate', () => {
            it('makes expected calls', () => {
                const authenticationServiceStub = () => ({ userValue: {} });
                const routerStubInit = () => ({ navigate: (array, object) => ({}) });
                TestBed.configureTestingModule({
                    imports: [HttpClientTestingModule],
                    providers: [
                        AuthGuard,
                        HttpClient,
                        HttpHandler,
                        { provide: Router, useFactory: routerStubInit },
                        { provide: AuthenticationService, useFactory: authenticationServiceStub }
                    ]
                });
                service = TestBed.inject(AuthGuard);
    
                const activatedRouteSnapshotStub: ActivatedRouteSnapshot = <any>{};
                const routerStateSnapshotStub: RouterStateSnapshot = <any>{};
                spyOn(service, 'canActivate').and.callThrough();
                service.canActivate(activatedRouteSnapshotStub, routerStateSnapshotStub);
                expect(service.canActivate).toHaveBeenCalled();
            });
    
            it('makes expected calls', () => {
                const routerStubInit = () => ({ navigate: (array, object) => ({}) });
                const authenticationServiceStubNull = () => ({ userValue: null });
                TestBed.configureTestingModule({
                    imports: [HttpClientTestingModule],
                    providers: [
                        AuthGuard,
                        HttpClient,
                        HttpHandler,
                        { provide: Router, useFactory: routerStubInit },
                        { provide: AuthenticationService, useFactory: authenticationServiceStubNull }
                    ]
                });
                service = TestBed.inject(AuthGuard);
    
                const routerStub: Router = TestBed.inject(Router);
                const activatedRouteSnapshotStub: ActivatedRouteSnapshot = <any>{};
                const routerStateSnapshotStub: RouterStateSnapshot = <any>{};
                spyOn(routerStub, 'navigate').and.callThrough();
                service.canActivate(activatedRouteSnapshotStub, routerStateSnapshotStub);
                expect(routerStub.navigate).toHaveBeenCalled();
            });
        });
    });

Any answer to this matter? I got into the same issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM