We are writing UI tests with cypress, which is usually quite simple to use. But again and again I stumble over a tedious waiting problem.
The scenario is pretty simple. The user clicks on the search button. Then he selects one of the elements with a certain text. Here's the code:
cy.get('#search-button').click();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
The third click event fails, because already cy.contains('Test item 1')
doesn't wait for the page and the element to be rendered. From what I can see in the test steps, it simply clicks in the middle of the page, which does essentially nothing. So all subsequent steps fail of course.
However if I add a wait()
between the calls like this:
cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
The page is rendered correctly, Test item 1
appears, is clicked and all subsequent steps succeed.
According the best practices the wait()
call should not be necessary and therefore should be avoided. What am I doing wrong here?
Give a bigger timeout for contains
:
cy.get('#search-button').click();
cy.contains('Test item 1', { timeout: 4000 }).click();
cy.get('#cheapest-offer-button').click();
As many Cypress commands, contains
have a second argument which accepts an option object. You can pass the amount of milliseconds the command should wait in the timeout
key like this:
.contains('Stuff', { timeout: 5000 }) // Timeout after 5 secs
This way the command will behave like if you added a wait
before it, but if the command was successful it won't wait out all the time like wait
does.
The official Cypress docs on timeouts explains this technique: how it works, how it should be done and how it affects chained assertions.
If the reason why you can't click the item is visibility then you can try .click({ force: true })
, although this should be a last resort since it might hide actual bugs.