Skip to content

waitForElement can leave its MutationObserver running for all future tests #357

Closed
@RoystonS

Description

@RoystonS
  • DOM Testing Library version: 5.5.0
  • node version: 10.16.0
  • npm (or yarn) 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?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions