Reputation: 10858
How do I debug the testing situation where await fixture.whenStable()
never resolves.
Put another way: what does this indicate about my component?
I have a spec that looks like this:
it('should open the modal when ?series is navigated to', async () => {
const { instance, fixture } = await _render();
const openSpy = spyOn(instance, 'openModal');
expect(openSpy).not.toHaveBeenCalled();
_updateQuery({ series: '' });
fixture.detectChanges();
// await fixture.whenStable(); // <- never resolves
expect(openSpy).toHaveBeenCalled(); // <- fails
});
(I need to use an actual async function to work with my testing library.)
Calling await fixture.whenStable()
hangs no matter where in the function body I put it – seems to indicate that the issue is present right when the component is loaded.
I don't really understand what whenStable()
even does. Perhaps if I did I could figure this out without help.
Upvotes: 2
Views: 8960
Reputation: 10858
In my particular case, the issue was that I assumed the lifecycle hook ngAfterViewchecked
only fired once, but actually fires repeatedly.
I was assigning a value to a field on my component inside of that handler, so the value of that field kept changing (because it needed to be calculated).
Because the value of the field changed things in the view, and that triggers ngAfterViewChecked
, and the JavaScript engine's task queue was being added to thereby, the state of the component could not become "stable".
@Component({ ... })
export class MyComponent {
listToRepeatOver = [];
ngAfterViewChecked() {
this.listToRepeatOver = getList();
}
}
I suspected something was up because I saw that purple flashing effect in the Elements panel of the Chrome devtools that indicates that DOM changed on an element inside my component template. (It was happening in rapid-fire succession).
Lesson being: If you make an update inside of a lifecycle hook which causes that lifecycle hook to fire again, then you'll get this result.
Upvotes: 2
Reputation: 99
According to https://angular.io/guide/testing
The fixture.whenStable() returns a promise that resolves when the JavaScript engine's task queue becomes empty.
So in this case:
class AppComponent implements OnInit {
someText: Observable<string>;
ngOnInit() {
this.someText = of('some string');
}
}
whenStable
resolves when observable in ngOnInit
emits it's value.
it('after onInit observable should be set', async(async () => {
component.ngOnInit();
await fixture.whenStable();
fixture.detectChanges();
console.log('after whenStable'); // <- now you gonna see this in console
}));
Upvotes: 1