Description
DOM Testing Library
version: 5.5.0node
version: 10.16.0npm
(oryarn
) version: yarn 1.16.0
Relevant code or config:
async function waitForListToBeReady(id: number) {
console.log('getCancelButton', id);
await waitForElement(() => {
console.log('running waitForElement predicate', id);
return getRowCount() === 44;
});
console.log('waitForElement', id, 'completed');
}
bdd.it('runs some stuff in test1', async () => {
doSomeSetup();
await waitForListToBeReady(1);
expect(something).to.be.true;
});
bdd.it('runs some stuff in test2', async () => {
doSomeSetup();
await waitForListToBeReady(2);
expect(something).to.be.true;
});
bdd.it('runs some stuff in test3', async () => {
doSomeSetup();
await waitForListToBeReady(3);
expect(something).to.be.true;
});
});
What you did:
Used waitForElement
in one test, with the Intern testing framework.
What happened:
Every test that calls waitForElement
causes another DOM MutationObserver to be created, and not cleaned up, and every DOM change causes all prior waitForElement
predicates to be re-evaluated. The tests get slower and slower.
The output:
getCancelButton 1
running waitForElement predicate 1
waitForElement 1 completed
running waitForElement predicate 1
getCancelButton 2
running waitForElement predicate 2
running waitForElement predicate 1
waitForElement 2 completed
running waitForElement predicate 1
running waitForElement predicate 2
getCancelButton 3
running waitForElement predicate 3
running waitForElement predicate 1
running waitForElement predicate 2
waitForElement 3 completed
running waitForElement predicate 1
running waitForElement predicate 2
running waitForElement predicate 3
running waitForElement predicate 1
running waitForElement predicate 2
running waitForElement predicate 3
[repeat a couple of hundred times as the test framework writes its output to the DOM]
This shows that, despite the fact that waitForElement
has completed, it's still listening for DOM changes and still re-evaluating its predicate.
Reproduction:
See above. A full repro would require setting up an Intern deployment, which I can do, but it'll take a little longer.
Problem description:
The tests get slower and slower as the number of DOM MutationObservers accumulates, especially as the existing test predicates start to cause exception throws.
Suggested solution:
I'm not sure. Looking at the code, it looks like waitForElement
uses setImmediate
to queue up the .disconnect
call of the MutationObserver, but it looks like, as my tests run, nothing ever yields sufficiently to allow this callback to run, so the .disconnect
call gets pushed back until all the tests complete. (I'm running on Chrome, which doesn't have native setImmediate
, so DTL is using a polyfill which uses postMessage
to simulate the effect.)
Removing the setImmediate
call would cause the MutationObserver to be shut down synchronously, and that would fix this issue, but I don't know why the setImmediate
call is there: presumably somebody added it for a good reason?