Search code examples
angularjasmine

Expected angular Route.navigate to have been called, but is never called


I'm having when spying on injected Router. I'm calling a component's method from the unit test. This method in turn calls Router.navigate. When expecting the Router.navigate spy to have been called, I'm getting a failure.

Component

@Component({
    selector: 'app-comp',
    standalone: true,
    imports: [],
    templateUrl: './comp.component.html',
    styleUrl: './comp.component.scss'
})
export class CompComponent implements OnInit {

    constructor(public router: Router, public route: ActivatedRoute) {}    

    changeCompNumber(newCompNumber: number) {
        this.router.navigate([], { queryParams: { 'comp': newCompNumber }, queryParamsHandling: 'merge'}
    }

}

unit test


describe('CompComponent', () => {
    let component: CompComponent;
    let fixture: ComponentFixture<CompComponent>;
    let ngZone: NgZone;
    let router: Router;

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [RouterTestingModule, CompComponent]
        }).compileComponents();

        fixture = TestBed.createComponent(CompComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        ngZone = TestBed.inject(NgZone);
        router = TestBed.inject(Router);
    });

   it("should change comp number", fakeAsync(() => {

        ngZone.run(() => {
            component.changeCompNumber(20);
            tick()
            fixture.detectChanges();
        });
        const navSpy = spyOn(router, "navigate");
        expect(navSpy).toHaveBeenCalled();
    }))
});

Error:

Expected spy navigate to have been called.

Solution

  • You are most likely spying too late. Try the following:

    it("should change comp number", fakeAsync(() => {
            // Spy here
            const navSpy = spyOn(router, "navigate");
            ngZone.run(() => {
                component.changeCompNumber(20);
                tick()
                fixture.detectChanges();
            });
            expect(navSpy).toHaveBeenCalled();
        }))
    

    Also, you most likely don't need the ngZone.run(()).

    it("should change comp number", fakeAsync(() => {
            // Spy here
            const navSpy = spyOn(router, "navigate");
    
            component.changeCompNumber(20);
            tick()
            fixture.detectChanges();
    
            expect(navSpy).toHaveBeenCalled();
        }))