39

I am writing a Cypress test to log in to a website. There are username and password fields and a Submit button. Mostly logins are straightforward, but sometimes a warning dialog appears first that has to be dismissed.

I tried this:

cy.get('#login-username').type('username');
cy.get('#login-password').type(`password{enter}`);

// Check for a possible warning dialog and dismiss it
if (cy.get('.warning')) {
  cy.get('#warn-dialog-submit').click();
}

Which works fine, except that the test fails if the warning doesn't appear:

CypressError: Timed out retrying: Expected to find element: '.warning', but never found it.

Then I tried this, which fails because the warning doesn't appear fast enough, so Cypress.$ doesn't find anything:

cy.get('#login-username').type('username');
cy.get('#login-password').type(`password{enter}`);

// Check for a possible warning dialog and dismiss it
if (Cypress.$('.warning').length > 0) {
  cy.get('#warn-dialog-submit').click();
}

What is the correct way to check for the existence of an element? I need something like cy.get() that doesn't complain if the element can't be found.

Manuel Abascal
  • 4,456
  • 3
  • 30
  • 51
Charles Anderson
  • 17,997
  • 13
  • 55
  • 73

5 Answers5

24
export function clickIfExist(element) {
    cy.get('body').then((body) => {
        if (body.find(element).length > 0) {
            cy.get(element).click();
        }
    });
}
Ran Adler
  • 3,355
  • 27
  • 27
  • 2
    Is there a way to set a timeout for finding the element? – dewey Feb 25 '22 at 12:23
  • @dewey The `find` method is a JQuery method, not a Cypress one, so it doesn't have any built-in timeouts. Here is a question regarding waiting until an element exists using JQuery or plain Javascript: https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists. I guess you could do something like this: `if (body.find(element).length == 0) {cy.wait(timeout);} if (body.find(element).length > 0) {cy.get(element).click();}` – M. Justin May 20 '22 at 19:17
2

There are various downsides to attempting to do conditional testing on DOM elements and also various workarounds in Cypress. All of this is explained in depth in the Cypress documentation in Conditional Testing.

Since there are multiple ways to do what you are trying to do, I suggest you read through the entire document and decide what is best for your application and your testing needs.

Jennifer Shehane
  • 5,806
  • 1
  • 28
  • 26
  • Thanks. I had a feeling I was approaching the problem wrongly. I now 'get' the body element (which must exist) and then test if it has the warning dialog below it. Works fine. – Charles Anderson Dec 14 '17 at 18:18
  • @CharlesAnderson could you share your test code? I need to do exactly the same thing – Ryan Langton Feb 21 '19 at 19:46
  • 35
    `cy.get('body').then((body) => { if (body.find('.warning').length > 0) { cy.get('#warn-dialog-submit').click(); } });` – Charles Anderson Mar 06 '19 at 15:36
  • 13
    How is this the accepted answer? There are valid use cases for doing conditional testing (e.g. server rendered DOM). This answer is little more than a slap on the wrist and link to the documentation. – charliefortune Jun 24 '21 at 10:37
  • This answer should either be deleted or removed by the community – Eugen Sunic Apr 22 '22 at 12:38
1
export const getEl = name => cy.get(`[data-cy="${name}"]`)

export const checkIfElementPresent = (visibleEl, text) => {
   cy.document().then((doc) => {
     if(doc.querySelectorAll(`[data-cy=${visibleEl}]`).length){
      getEl(visibleEl).should('have.text', text)

      return ;
   }
getEl(visibleEl).should('not.exist')})}
M. Justin
  • 9,474
  • 3
  • 68
  • 98
0

I have done it with pure js.

cy.get('body').then((jqBodyWrapper) => {

               if (jqBodyWrapper[0].querySelector('.pager-last a')) {
                   cy.get('.pager-last a').then(jqWrapper => {
                       // hardcoded due to similarities found on page

                       const splitLink = jqWrapper[0].href.split("2C");
                       AMOUNT_OF_PAGES_TO_BE_RETRIEVED = Number(splitLink[splitLink.length - 1]) + 1;
                   })
               } else {
                   AMOUNT_OF_PAGES_TO_BE_RETRIEVED = 1;
               }
           });

I'm trying to check if element exists on body

cy.get('body').then((jqBodyWrapper) => {

With a pure js querySelector

if (jqBodyWrapper[0].querySelector('.pager-last a')) {

Then I fire my cy.get

cy.get('.pager-last a').then(jqWrapper => {
M. Justin
  • 9,474
  • 3
  • 68
  • 98
Patryk Janik
  • 2,245
  • 1
  • 10
  • 21
0

The hasClass() or for CSS selector has() is an inbuilt method in jQuery which checks whether the elements with the specified class name exists or not. You can then return a boolean to perform assertion control.

Cypress.Commands.add('isExistElement', selector => {
  cy.get('body').then(($el) => {
    if ($el.has(selector)) {
      return true
    } else {
      return false
    }
  })
});

Then, it can be made into a special cypress method with TypeScript file (index.d.ts) file and can be in the form of a chainable.

declare namespace Cypress {
    interface Chainable {
        isExistElement(cssSelector: string): Cypress.Chainable<boolean>
    }
}

As in the example below:

  shouldSeeCreateTicketTab() {
    cy.isExistElement(homePageSelector.createTicketTab).should("be.true");
  }
double-beep
  • 4,567
  • 13
  • 30
  • 40
ogulcan
  • 1
  • 1