1

Given the following Cypress v10.9.0 spec:

  it('can search the database', () => {
    cy.get('[data-cy=searchInput]').type('my search');
    cy.get('[data-cy=searchOutput]').contains('Searching...');
    cy.wait(5000);
    cy.get('[data-cy=searchOutput]')
      .children('div')
      .should('have.length', 20);
  });

This test works. I am fairly new to Cypress. My question is what is the best practice for waiting on an API to return before asserting the results? I am using cy.wait(5000); which does work ok. I would prefer if the assertion would start trying immediately and fail after a timeout period. I don't see any such option. Like this:

.should('have.length', 20, {timeout: 5000});

This would give me a similar effect and be more optimized. Because the assertion could return before the timeout. The cy.wait(5000) method will always block for the full 5 seconds.

Is there a faster way to run these kinds of tests?

2 Answers 2

2

There are many options depending on the application you are testing. Being proficient in Cypress essentially means mastering the waits. Some of the options:

  • A fixed timeout (wait) before trying. This can work but introduces fixed delays which makes the test suite slow. At a certain point a slow test suite does not add much value as it can not be used as part of the development workflow if the feedback is not fast enough to keep the developer(s) in flow. Aim for under 10 minutes and use parallelization and the agile testing pyramid as tools to help and guide this effort. parallelization means a strong control over the data being used so that tests are atomic and not affected by other tests.

  • An inline timeout as shown by João Farias

  • An intercept. This is the more advanced functionality that Cypress provides to deal with these issues.

  • a combination of multiple approaches. Sometimes you will need to combine the techniques for the best results, for example a short fixed wait followed by an inline timeout wait or an intercept may be a good solution.

Note that timing is THE hard part of writing test automation.
It will require a constant and intense effort. It is never 'solved' permanently.

The primary challenge for such timing issues will be the way your application is written and the framework it is written in. A common issue with frameworks such as React is that the application issues async calls and when they come back they update the DOM. In some cases the DOM may meet the condition that the test is expecting... but the data is still coming back asynchronously for the actual result that needs to be verified. In these cases you will need to consider a fixed wait so the application has more time to get to the state you need or an intercept. In some cases a fixed wait is the only option that works. Be aware that many application developers will push to remove various sleeps but without reliability testing - say, running the test 100 times locally and in CI, the result will frequently be a flaky and unreliable test suite.

Finally, despite your best attempt a test may fail. Consider setting CI retries for 2 or 3 attempts because no single test is worth the suite failing and if the suite fails it loses credibility

1
  • This helped me out a lot. Like mentioned in another answer, the final piece that I didn't understand was Cypress supports a concept they call retry-ability. The assertions are retried until they pass or the previous command times out: docs.cypress.io/guides/core-concepts/retry-ability Commented Sep 29, 2022 at 12:53
3

You can pass a timeout argument.

cy.get('[data-cy=searchOutput]', { timeout: 10000 }).contains('Searching...');
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.