I'm developing an angular exercising app and testing it with Karma and Jasmine. I'm trying to test router's navigate functionality. The problem is that this call is inside a then(). I suppose something is not working because is async. The error: Expected spy navigate to have been called with:[ [ '/error' ] ] but it was never called. How can I resolve it? My ts:
myFunction(): void {
functionWhichReturnsPromise().then(() => {
this.router.navigate('/error');
});
}
Spec file:
describe('myComponent', () => {
let component: myComponent;
let fixture: ComponentFixture<myComponent>;
let router: Router;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [myComponent],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
fixture = TestBed.createComponent(myComponent);
router = TestBed.inject(Router);
component = fixture.componentInstance;
spyOn('functionWhichReturnsPromise').and.returnValue(Promise.resolve());
fixture.detectChanges();
});
it('should call navigate', () => {
const spyRouter = spyOn(router, 'navigate').and.resolveTo(true);
component.myFunction();
expect(spyRouter).toHaveBeenCalledWith(['/error']);
});
});
Angular lets you synchronously simulate the passing of time of an async function by wrapping your test function in fakeAsync
, then using tick(ms)
where ms is the number of millisecond you want ellapsed.
With your code:
it('should call navigate', fakeAsync(() => {
const spyRouter = spyOn(router, 'navigate').and.resolveTo(true);
component.myFunction();
tick() //might need to specify a number of millisecond
//depending on what 'myFunction' does
expect(spyRouter).toHaveBeenCalledWith(['/error']);
}));
FakeAsync doc
Note that in you case, depending on what your promise does, flushMicrotasks()
might also work instead of tick()