Cypress : How can I check if an element exists without failing the test if it doesnt?

Viewed 9318

Ok, here is my situation:

On the website that I'm testing, A part of my tests include a table where user's can add or delete rows. I cannot control if the table will be empty or not, so I need to have conditionals (IF) to explore two scenarios: 1. The table is empty; 2. The table is not empty.

What I came up with is just to check if the first row of the table exists. If it does, do some tests and then proceed, and if it doesn't just skip the table and proceed to the next texts.

Of course, I CANT just try to do a cy.get on the first row, because if it doesnt find the element, it is going to fail the test, so I tried this:

             cy.get('body').then(($body) => {
                 if ($body.find('firstRowElement').length > 0,  {timeout: 60000}) { 
                    cy.log("Im Inside")
                    cy.get('firstRowElement').then(($grid) => {  
                        //Do all the tests I need if the first row exists..
                    )}
                 } 
             )}

BUT IT DOESNT WORK. Even when the table is empty, it still enters the IF (I can see the log "Im inside"). Then, of course, on the next line (already inside the IF) the test fails because it tries to do a cy.get on an element that does not exist (first row of an empty table). So, it seems simply that the IF statement is not working.

What am I doing wrong?

PS: I need the timeout because the table takes a few seconds to load. I tried moving the timeout to inside the .find (like this - if ($body.find('firstRowElement', {timeout: 60000}).length > 0) but its even worse. When it is like this, it simply doesn't wait and skip everything because the table wasn't loaded yet. I also don't want to use cy.wait

Anybody can help me?

I'm inclined to believe that there is some sort of conflict between .find and timeout.

2 Answers

You can try this approach, very bare bones but it gives you an idea on how to conditionally test something like that. They key element is to work with what you see. As suggested above you really want to have something like waitUntil for future reference in your project.

cy.get('parent element of matrix or body').then($body => {
 cy.waitUntil(() => cy.get('parent element of first row')
 .then($selector => $selector.is(':visible') === true), { timeout: 60000 })
 if ($body.find('first Row Element').is(':visible')) {
  cy.log('A row exists')
 } else {
  cy.log('A row doesnt exists')
 }
})   

If you want to conditionally test for an element without failing, the generally accepted approach is to use a jQuery expression (as you have done, but see my comment above about the timeout option thwarting that approach).

I assume because you apply a timeout that the table row may or may not eventually show up, and you will wait up to 60 seconds.

One approach to conditionally test but also make use of Cypress retry is to use the fail event, an example of which is here Assert that element is not actionable in Cypress.

It's recommended only to use on('fail') to debug, but is used in the Cypress own test - you should choose if you want to ignore the warning.

Something like

it('...', (done) => {

  cy.once('fail', () => {
    // Skipping if the command below fails (i.e first row does not exist)
    done();  // done tells the test it ends here
  });

  cy.get('firstRowElement', { timeout: 60000 }).then(($grid) => {
    // Do all the tests I need if the first row exists..
    done();
  )}

});
Related