Reputation: 1796
I have been reading a lot about angular testing lately and the pairs are always async+fixture.whenStable and fakeAsync+tick, however you can always call fixtrue.whenStable as it is not tightly coupled. If you call it when not using the async utility to track promises in a test zone will it actually do anything?
For example:
it('should be able to do this thing that needs some async setup', () => {
fixture.detectChanges();
fixture.whenStable().then()
});
I understand the difference between FakeAsync/Tick
and fixture.detectChanges
. My question is regarding what fixture.whenstable
will do when inside of a FakeAsync
execution zone as an Async
zone should keep track of async work allowing fixture.whenstable
to hook into that tracking, at least as I understand it. Or indeed if used and not within an async execution zone at all.
So if fixture.whenstable is used inside a FakeAsync function, or a function that does not setup an async execution zone, will it work as intended?
Upvotes: 36
Views: 44401
Reputation: 27304
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...)
Upvotes: 12
Reputation: 3776
try to wrap your test code into waitForAsync
this is new recommended way to test async code in angular
@Component()
export class SomeComponent implements OnInit {
async ngOnInit() {
// to test component with async ngOnInit use waitForAsync
}
}
beforeEach(
waitForAsync(() => {
fixture = TestBed.createComponent(SomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
})
);
Upvotes: 1
Reputation: 12082
No the whenStable()
does nothing if you test without async
or 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.
Upvotes: 43