Does fixture.whenStable() actually do anything in my angular tests if not within an async test execution zone?

No the whenStable() does nothing if you test without async of fakeAsync. What whenStable() does is to wait for all tasks in the test NgZone to complete. When you don't test with async the NgZone does not get created at all and whenStable() just returns immediately.

If you want more detail check the code for ComponentFixture in GitHub.


The accepted answer may have been correct when it was written, but as of late 2020, when using node_modules/zone.js/bundles/zone-testing.umd.js, I don't think it is anymore. I can't find a citation in the docs, but I can confirm experimentally that a test zone is always used, and that whenStable waits for its tasks to complete.

This is very simple to try for yourself. Just create an empty test, and add

//// In my.component.ts
import { timer } from "rxjs";
import { map } from "rxjs/operators";

@Component({
  template: `<p>{{clock|async}}</p>,
  ...
})
export class MyComponent {
  /** @internal */ public readonly clock = timer(0,1000).pipe(map(() => new Date()));
}


//// In `my.component.spec.ts`
beforeEach(async () => {
    testBed.configureTestingModule(...);
    await testBed.compileComponents();
    fixture = testBed.createComponent(MyComponent);
    await fixture.whenStable();
});

Because rxjs timer uses setInterval under the hood, it's flagged as always having a pending task, so whenStable never resolves. Jasmine will fail with a timeout, waiting for the Promise returned by the setup method to resolve. (Ask me how I discovered this...)