⚪ ️ 3.4 Don’t sleep, use frameworks built-in support for async events. Also try to speed things up

:white_check_mark: Do: In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. Cypress cy.request(‘url’)), other provide API for waiting like @testing-library/dom method wait(expect(element)). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to hurry-up the clock. Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there’s no support from the testing framework, some npm libraries like wait-for-expect can help with a semi-deterministic solution

Otherwise: When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn’t respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance


Code Examples

:clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress)

// using Cypress
cy.get("#show-products").click(); // navigate
cy.wait("@products"); // wait for route to appear
// this line will get executed only when the route is ready

:clap: Doing It Right Example: Testing library that waits for DOM elements

// @testing-library/dom
test("movie title appears", async () => {
  // element is initially not present...
 
  // wait for appearance
  await wait(() => {
    expect(getByText("the lion king")).toBeInTheDocument();
  });
 
  // wait for appearance and return the element
  const movie = await waitForElement(() => getByText("the lion king"));
});

:thumbsdown: Anti-Pattern Example: custom sleep code

test("movie title appears", async () => {
  // element is initially not present...
 
  // custom wait logic (caution: simplistic, no timeout)
  const interval = setInterval(() => {
    const found = getByText("the lion king");
    if (found) {
      clearInterval(interval);
      expect(getByText("the lion king")).toBeInTheDocument();
    }
  }, 100);
 
  // wait for appearance and return the element
  const movie = await waitForElement(() => getByText("the lion king"));
});