Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test Angular2's router.navigate?

I've run into missing <router-outlet> messages in other unit tests, but just to have a nice isolated example, I created an AuthGuard that checks if a user is logged in for certain actions.

This is the code:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {     if (!this.authService.isLoggedIn()) {         this.router.navigate(['/login']);         return false;     }     return true; } 

Now I want to write a unit test for this.

This is how I start my test:

beforeEach(() => {     TestBed.configureTestingModule({         imports: [             RouterTestingModule.withRoutes([                 {                     path: 'login',                     component: DummyComponent                 }             ])         ],         declarations: [             DummyComponent         ],         providers: [             AuthGuardService,             {                 provide: AuthService,                 useClass: MockAuthService             }         ]     }); }); 

I created a DummyComponent that does nothing. Now my test. Pretend that the service returns false and that it triggers this.router.navigate(['/login']):

it('should not let users pass when not logged in', (): void => {     expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false); }); 

This will throw an exception with "Cannot find primary outlet to load". Obviously I can use toThrow() instead of toBe(false), but that doesn't seem like a very sensible solution. Since I'm testing a service here, there is no template where I can put the <router-outlet> tag. I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule? Perhaps you even want to check that navigation worked.

like image 356
Bart Avatar asked Oct 28 '16 07:10

Bart


People also ask

How do I test a router navigate in Angular 8?

We can test routing in Angular by using RouterTestingModule instead of RouterModule to provide our routes. This uses a spy implementation of Location which doesn't trigger a request for a new URL but does let us know the target URL which we can use in our test specs.

How do you write a test case for router navigate in Angular jest?

router = TestBed. get(Router); Then, in the testcase, it('should show news intially ', () => { const navigateSpy = spyOn(router,'navigate'); component.

How does Angular router navigate work?

Angular router traverses the URL tree and matches the URL segments against the paths configured in the router configuration. If a URL segment matches the path of a route, the route's child routes are matched against the remaining URL segments until all URL segments are matched.


2 Answers

I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule? Perhaps you even want to check that navigation worked.

There's no real point. If his is just a unit test for the auth guard, then just mock and spy on the mock to check that it's navigate method was called with the login argument

let router = {   navigate: jasmine.createSpy('navigate') }  { provide: Router, useValue: router }  expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false); expect(router.navigate).toHaveBeenCalledWith(['/login']); 

This is how unit tests should normally be written. To try to test any actual real navigation, that would probably fall under the umbrella of end-to-end testing.

like image 105
Paul Samsotha Avatar answered Sep 20 '22 00:09

Paul Samsotha


If you want to test the router without mocking it you can just inject it into your test and then spy directly on the navigate method there. The .and.stub() will make it so the call doesn't do anything.

describe('something that navigates', () => {     it('should navigate', inject([Router], (router: Router) => {       spyOn(router, 'navigate').and.stub();       expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);       expect(router.navigate).toHaveBeenCalledWith(['/login']);     }));   }); 
like image 45
Chris Putnam Avatar answered Sep 19 '22 00:09

Chris Putnam