IMeyers20
IMeyers20

Reputation: 211

Angular 17 fakeAsync tasks not running until test is cleaned up with 'resetFakeAsyncZone()'

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
Helpful Resources

Upvotes: 1

Views: 396

Answers (1)

IMeyers20
IMeyers20

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

Related Questions