Overview
I am in the progress of migrating my Angular project from v14 to v17, and also migrating my Jest from v27 to v29 at the same time. I have my project running, with no console errors / warnings, but I am struggling to get Jest to work.
I am running my tests using the fakeAsync wrapper, but am getting an issue where some of the async tasks within aren’t ran until after any of my expect(...)
checks fail and Angular’s resetFakeAsyncZone()
runs, despite having all the necessary flush
/ tick
calls (this test passed before and breakpoints can show that it is still getting the same data but just not until after the expect call)
One of my failing tests
it('should call Update on submit if shouldUpdate is true', fakeAsync(() => {
// arrange
comp.shouldUpdate = true;
comp.CanAlter = true;
jest.spyOn(connectionResource, 'Update').mockImplementation((c) => {
return Promise.resolve({ ...c, Id: connection.Id, Children: [] } as ApiConnection);
});
let onSubSpy = jest.spyOn(comp.onSubmit, 'emit');
// act
comp.ngOnChanges();
flush();
fixture.detectChanges();
let result = { ...comp.form.getRawValue(), ParentId: probe.Id };
let submitButton = fixture.debugElement.query(By.css('button[type="submit"]'));
submitButton.nativeElement.click();
flush();
// assert
expect(connectionResource.Update).toHaveBeenCalledWith(result, connection.Id);
let cached = coreCache.SearchMonitorableTree(coreCache.PayloadCache.Monitorables[0], 'Id', connection.Id)[0];
expect(onSubSpy).toHaveBeenCalledWith(cached); // This expect fails, and the the spied function is hit directly after
}));
What I have tried so far
-
I have tried changing the expect to
toHaveBeenCalled()
to double check that there wasn’t some small change to the model somewhere, it insisted that it wasn’t called, then called it right after (same problem) -
I tried using
jest.useFakeTimers()
(there were many changes to fakeTimers in the last couple Jest updates), this did not fix. -
I tried adding
tick()
andflushMicrotasks()
to see if those would have any affect, they did not. -
I tried calling
resetFakeAsyncZone()
to see if that had any affect as that is what seems to cause it to work at the end, that did not work.
Helpful Resources
-
Here is a gif of what the bug looks like in action:
-
Here is the Angular Update Guide with breaking changes (Didn’t see anything with fakeAsync): https://update.angular.io/?l=3&v=14.0-17.0
-
Here is the Jest changelog with all the breaking changes: https://github.com/jestjs/jest/blob/main/CHANGELOG.md