Skip to content

Pending microtasks are not detected in fakeAsync() #31697

@hecht-software

Description

@hecht-software

I posted this question on SO, because I thought I'm doing something wrong:
https://stackoverflow.com/questions/52255528/how-to-detect-missing-tick-in-fakeasync

A user in the comments suggested submitting an issue here.

I have a problem with one of my unit tests. It tests a "delete" component method, which should show a confirmation dialog allowing the user to confirm or abort the delete action. The test expects the delete() service method not to have been called, if the user declines the delete action:

it('should request confirmation before deleting & abort action if user declined', fakeAsync(() => {
    spyOn(appService, 'confirm').and.returnValue(of(false));
    spyOn(personService, 'delete').and.callThrough();
    component.deleteEntry(testPerson);
    //tick(); // Missing tick()!
    expect(personService.delete).not.toHaveBeenCalled();
}));

confirm() returns an Observable that emitts true/false depending on the user's decision. A spy on confirm() will simulate the user declining the action (of(false)). As you can see in the code above tick() is commented out - let's assume the test dev simply forgot it.

Of course our expectation will now always be fulfilled. The Observable provided by confirm() won't emit anything, since the microtask is pending at the time expect() is called.

However, I expected fakeAsync() to throw an exception as the docs say:

If there are any pending timers at the end of the function, an exception will be thrown.

Here is the code for the component function I'm testing:

deleteEntry(person: Person) {
  this.appService.confirm().toPromise().then(
    (value) => {
      // Bug here: "!" operator is missing before "value":
      if (value) {
        return;
      }
      return this.personService.delete(person).toPromise();
    }
  ).catch((e) => {
    console.error(e);
  });
}

This test is crucial. It would be a big problem, if entities are deleted, just because the developer forgot a "!". Actually, this is why we write tests.

Also see my reproducing project on stackblitz. Notice that you have to click the 'refresh'-button of the inner browser view (next to the editor) if you want to re-run the test or after you changed something. The auto-reload feature will not work and throw errors.

Metadata

Metadata

Assignees

Labels

area: zonesIssues related to zone.jsfeatureLabel used to distinguish feature request from other issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions