Description
Hello 👋,,
we have the issue that some of our testing-library tests get stuck in an endless loop but only when they fail.
I could track down the issue to the waitFor function and to all functions that use it under the hood such as findBy*
.
Furthermore, I think the issue is related to the internal usage of MutationObserver in waitFor by DTL to trigger the callback inside waitFor. But also how ATL wraps the waitFor function.
One idea i have that it might be related to this issue in DTL that suggests that you shouldn't do DOM mutations inside the waitFor but this is what can happen in the detectChanges call:
https://github.com/testing-library/angular-testing-library/blob/main/projects/testing-library/src/lib/testing-library.ts#L314
You can reproduce the issue in this simple test:
@Component({
selector: 'atl-fixture',
template: `
<button [ngClass]="classes">Load</button>
`,
})
class LoopComponent {
get classes() {
return {
someClass: true,
};
}
}
test('does not end up in a loop', async () => {
await render(LoopComponent);
await waitForATL(() => {
expect(true).toEqual(false);
});
});
This should time out but is stuck in a loop. If I manually remove the mutationObserver code in the waitFor function from testing-library-dom the issue is gone. However, I think this issue still belongs to this library as it is angular specific.
Edit: This issue in the angular repository might also indicate what is going wrong here
Edit2: I'm pretty sure now it works like this: ATL detectChanges causes CD cycle => get classes() returns new object => DOM mutation => mutationObserver triggers => DTL triggers callback => triggers ATL detectChanges again. My solution for now is to remove MutationObserver code from DTL using patch-package as I prefer slower tests to reliable tests. We could open request to DTL to make mutationObserver optional, or maybe you have a better idea. I'm also willing to create a PR if we can come up with a feasible solution.