Reputation: 211
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)
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
}));
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()
and flushMicrotasks()
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.
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
Upvotes: 1
Views: 396
Reputation: 211
So the issue was that fakeAsync
is based on patching async
/await
which is possible until ES2016. Our tsconfig.spec.json
we were using was configured to target ES2022.
In my tsconfig.spec.json
files, I made sure to use 'CommonJS'
as the module, and targeted ES2016. Going forward, if I want to use a higher ES version, I will need to rework my tests a bit:
https://stackoverflow.com/a/79092586/21644695
Old tsconfig.spec.json
:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "CommonJS",
"target": "ES2022",
"types": ["jest", "node", "chart.js"],
"typeRoots": ["./types", "node_modules/@types"],
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"include": [
"apps/**/*.spec.ts",
"libs/**/*.spec.ts",
"types/**/*",
"tools/**/*.spec.ts"
]
}
New tsconfig.spec.json
:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "CommonJS",
"target": "ES2016",
"types": ["jest", "node", "chart.js"],
"typeRoots": ["./types", "node_modules/@types"],
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"include": [
"apps/**/*.spec.ts",
"libs/**/*.spec.ts",
"types/**/*",
"tools/**/*.spec.ts"
]
}
If you run into this issue, just make sure that wherever you are configuring compilerOptions
for your tests, that you do not use ES2022
, downgrade it to ES2015
or ES2016
Upvotes: 1