lecture 9 of 170 completed

Waiting properly

A fixed pause is a guess. Too short and the test fails; too long and every run wastes time.

Saving a contact takes about 700 milliseconds. So the obvious thing to write is this:

cy.get('[data-testid="save-contact"]').click();
cy.wait(1000);
cy.get('[data-testid="toast"]').should('contain', 'Contact created');

Wait one second, then check. It works on your machine. Please do not do it, and here is why.

A fixed pause is a guess about how long something takes, and you lose that guess in both directions.

When it is too short, the test fails for no real reason. Your laptop is fast. The build server is usually slower and busier. A pause that always works locally will fail there.

When it is too long, you pay for it forever. One extra second in eighty tests is more than a minute added to every single run.

The right approach is to wait for the thing you actually want, not for time. In Cypress you already have it:

cy.get('[data-testid="save-contact"]').click();
cy.get('[data-testid="toast"]').should('contain', 'Contact created');

Cypress retries this. It looks for the toast again and again until it appears or the timeout is reached. If the save takes 200ms, your test continues after 200ms. If it takes 3 seconds, it waits 3 seconds.

One important detail. There are two different things called cy.wait:

  • cy.wait(1000) waits for a number of milliseconds. This is the one to avoid.
  • cy.wait('@saveContact') waits for a specific network request to finish. This one is good practice, and you will learn it in the intermediate track.

So when you see cy.wait with a number in a code review, treat it as a small bug. There is almost always a condition you could wait for instead.

Remember this: wait for a condition, never for a number.

Reference: Retry-ability.

now prove it

Reading is the setup. Solve these problems in the editor. We break the app on purpose to check your test would catch it.