Unit testing button with routerLink directive

Viewed 455

I have a simple static view that I would like to write tests for:

<div class="landing-page">
 <app-cover>
   <app-stack [large]="true">
     <app-center> 
       <img src="assets/images/logo.svg" />
     </app-center>
     <app-center>
       <p>
         Try matching the employee to their photo.
       </p>
     </app-center>
     <app-center>
       <app-button routerLink="namegame">
         Play!
       </app-button>
     </app-center>
   </app-stack>
 </app-cover>
</div>

I was able to make assertions that the text of the <p> tag and the <button> are accurate easily. However, I am having trouble writing a unit test for the button behavior, e.g. when I click on the button I get navigated to the /namegame route.

The message I see from Karma is really confusing:

Chrome 83.0.4103.106 (Mac OS 10.15.5) NamegameComponent navigates to /namegame when the "Play" 

button is clicked FAILED
Expected spy navigateByUrl to have been called with:
 [ '/namegame', <jasmine.anything> ]
but actual calls were:
 [ /namegame, Object({ skipLocationChange: false, replaceUrl: false, state: undefined }) ].
Call 0:
 Expected $[0] = /namegame to equal '/namegame'.

Test code:

// ... imports ...

describe('NamegameComponent', () => {
 let component: LandingPageComponent;
 let fixture: ComponentFixture<LandingPageComponent>;
 let router: Router;

 beforeEach(async(() => {
   TestBed.configureTestingModule({
     imports: [RouterTestingModule.withRoutes([])],
     declarations: [
       LandingPageComponent,
       CenterComponent,
       CoverComponent,
       StackComponent,
       ButtonComponent,
     ],
   }).compileComponents();
 }));

 beforeEach(() => {
   fixture = TestBed.createComponent(LandingPageComponent);
   component = fixture.componentInstance;
   router = TestBed.inject(Router);
   fixture.detectChanges();
 });

 // ... other tests ...

 it('navigates to /namegame when the "Play" button is clicked', () => {
   const navSpy = spyOn(router, 'navigateByUrl');
   const button = fixture.nativeElement.querySelector('app-button');
   button.click();
   expect(navSpy).toHaveBeenCalledTimes(1);
   expect(navSpy).toHaveBeenCalledWith(`/namegame`, jasmine.anything());
 });
});

Any ideas why the assertion doesn't match? Is there something wrong with the quoting?

2 Answers

The issue turned out to be that navigateByUrl is called with a UrlTree not a string like I expected initially.

Either one of these assertions will work:

// matching the UrlTree directly
expect(navSpy).toHaveBeenCalledWith(
  router.createUrlTree(['/namegame']), 
  jasmine.anything()
);

or

// explicitly convert the UrlTree to a string before comparison
expect(navSpy.calls.mostRecent().args[0].toString()).toEqual('/namegame');

I can only assume it's because you are using backticks instead of normal quotes. Try:

expect(navSpy).toHaveBeenCalledWith('/namegame', jasmine.anything());
Related