Hi i m new to Cypress and i try to avoid the wait()
function on my tests..
I m aware, based on the official docs, that Cypress works async and wedont need to use the wait()
function, especially the visit()
command handles that because it loads the page and then it moves on.
On my test case i want to do 2 main things that cause an issue:
- open a dropdown menu (its on the Left nav menu, which there are 5 menus and i want the 2nd)
- click on an option to go to another page
it("clicks on the 'Front End' and navigates to the correct page", () => {
visit(path, {
timeout: 120000,
pageLoadTimeout: 120000,
});
cy.get(selectors.CATEGORIES)
.eq(2)
// i use 'within', because i want to search **inside the selectors.CATEGORIES.eq(2) and not on the whole DOM**
.within(() => {
cy.get(dataCySelector("gridRow")).then(($optionsWrapper) => {
const parentEl = $optionsWrapper.parent();
const isMenuOpen = parentEl.css("display");
// if i dont add the wait(), it selects the 1st 'menu options' instead of the **3rd**
cy.wait(3000);
if (isMenuOpen === "none") {
console.log("*MENU IS CLOSE I OPEN*");
cy.contains("category").click(); // OPEN THE MENU
cy.contains("Front End").should("be.visible").click(); // click on the 'front end'
} else {
console.log("*MENU IS OPEN I DONT CLICK ON IT*");
cy.contains("Front End").should("be.visible").click(); // JUST click on the 'front end'
}
cy.url().then(() => {
cy.urlIncludes("/path/to/menu/option");
cy.wait(3000);
cy.contains(dataCySelector("AN_ELEMENT"));
});
});
});
});
So the flow that i have is the below:
- visit the page that i want
- get the
CATEGORIES
selector (there are 5 menus on the left nav bar) - get the 3rd
- Use
within
so to drill down in into its children (i replacedthen
because it searched on the whole DOM instead)!! - i get the parent of the ‘gridRow’ and look if
display=none
- ! if i dont add the
wait(3000)
, theparentEl
is the first menu wrapper!! - After the comparison, click on the ‘option link’
- the user is redirected to the new page, but again i need the
wait()
so to check if the element selector exists.
Something must be wrong in here, can i get rid of the wait
s ?
thanks.
2
Answers
For the second
wait()
, if your problem is linked to the fact that your page needs more time to load than the default timeout, you can still override it.For the first
wait
, the If/Else is pretty weird. It should be known when it’s opened or not, so I would avoid it (by creating for example 2 functions, for both cases) and then, for each case, I would add a{timeout: 30_000}
where it’s necessary.In general, changing
.then()
to.should()
will give you retry and remove the need to wait.Retry is the smart way of waiting since it only waits as long as the condition is not met.
You must use
expect()
orassert()
to trigger the retry. Cypress patches thosechai
methods and uses the error thrown to trigger each retry attempt.Checking the URL
Checking the visibility of gridRow parent
You have a clean page load at the top of the test, so your menu will not be open initially (the page should load predictably).
The test could simply be:
But for the purpose of illustration, this should open the menu if not already open.
The note it selects the 1st ‘menu options’ instead of the 3rd seems to indicate the menu items are lazy-loaded.
You can overcome that by adding a
.should()
assertion for the number of menu options (length property).The whole test
You want to "decouple" steps so you can check them individually.
It’s hard to be exact about the code since you have abstracted the basic Cypress commands into custom commands, and not given details, but here’s the approach I would take: