89

How to check if element is present or not, so that certain steps can be performed if element is present. Else certain different steps can be performed if element is not present.

I tried something like below but it didn't work:

Cypress.Commands.add('deleteSometheingFunction', () => {
  cy.get('body').then($body => {
    if ($body.find(selectors.ruleCard).length) {
      let count = 0;
      cy.get(selectors.ruleCard)
        .each(() => count++)
        .then(() => {
          while (count-- > 0) {
            cy.get('body')
            // ...
            // ...
          }
        });
    }
  });
  });

I am looking for a simple solution, which can be incorporated with simple javascript if else block or then() section of the promise

Something similar to Webdriver protocol's below implementions:

  1. driver.findElements(By.yourLocator).size() > 0
  2. check for presenece of element in wait

Kindly advise. Thanks

axel
  • 3,778
  • 4
  • 45
  • 72
user2451016
  • 1,857
  • 3
  • 20
  • 44
  • 1
    Does this answer your question? [How to check for an element that may not exist using Cypress](https://stackoverflow.com/questions/47773525/how-to-check-for-an-element-that-may-not-exist-using-cypress) – Michael Freidgeim Jun 07 '20 at 11:05

11 Answers11

126

I'll just add that if you decide to do if condition by checking the .length property of cy.find command, you need to respect the asynchronous nature of cypress.

Example: Following condition evaluates as false despite appDrawerOpener button exists

    if (cy.find("button[data-cy=appDrawerOpener]").length > 0)    //evaluates as false

But this one evaluates as true because $body variable is already resolved as you're in .then() part of the promise:

    cy.get("body").then($body => {
        if ($body.find("button[data-cy=appDrawerOpener]").length > 0) {   
            //evaluates as true
        }
    });

Read more in Cypress documentation on conditional testing

DurkoMatko
  • 5,238
  • 4
  • 26
  • 35
  • 8
    thanks @DurkoMatko This should be the correct answer. – Realdo Dias Jun 26 '20 at 08:46
  • 1
    Thanks, buddy! This is a working solution. this should be the accepted answer. – Raj Jan 13 '21 at 16:35
  • 2
    The docs say `cy.find('.progress') // Errors, cannot be chained off 'cy'`. Did you mean `if (cy.get("button[data-cy=appDrawerOpener]")...`? (Does not change that the answer is correct). –  Mar 08 '21 at 19:04
  • 10
    The if statement .length does not work any more – Ashok kumar Ganesan Oct 01 '21 at 11:49
  • 2
    @AshokkumarGanesan works for me since long time :) and still this is a good solution – harmider Jan 07 '22 at 06:57
  • @AshokkumarGanesan It doesn't work for me too. Did you find another solution? – Rsaleh Jan 25 '22 at 18:45
  • I don't understand how your solution if different from the one in the question. In the question also the Author as used ```cy.get('body').then( )``` you have also done the same. Can you please explain why your solution is correct? – AnandShiva Aug 05 '22 at 04:03
14

it has been questioned before: Conditional statement in cypress

Thus you can basically try this:

cy.get('header').then(($a) => { 
        if ($a.text().includes('Account')) {
            cy.contains('Account')
            .click({force:true})
        } else if ($a.text().includes('Sign')) { 
            cy.contains('Sign In')
            .click({force:true})  
        } else {
            cy.get('.navUser-item--account .navUser-action').click({force:true})
        }
    })
Mr. J.
  • 3,499
  • 1
  • 11
  • 25
10

cypress all steps are async ,, so that you should make common function in commands file or page object file,,..

    export function checkIfEleExists(ele){
    return new Promise((resolve,reject)=>{
        /// here if  ele exists or not
        cy.get('body').find( ele ).its('length').then(res=>{
            if(res > 0){
                //// do task that you want to perform
                cy.get(ele).select('100').wait(2000);
                resolve();
            }else{
                reject();
            }
        });
    })
}


// here check if select[aria-label="rows per page"] exists
cy.checkIfEleExists('select[aria-label="rows per page"]')
.then(e=>{
        //// now do what if that element is in ,,..
        })
.catch(e=>{
    ////// if not exists...
    })
Manthan Patel
  • 260
  • 4
  • 9
6

I found a solution, hope it helps!

You can use this:

cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('Object value = ' + identifiedElement)
    });

You can add this to your commands.js file in Cypress

Cypress.Commands.add('isElementExist', (element) => {

    cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('Object value = ' + identifiedElement)
    });
})
3

Cypress official document has offered a solution addressing the exact issue.

How to check Element existence

// click the button causing the new
// elements to appear
cy.get('button').click()
cy.get('body')
  .then(($body) => {
    // synchronously query from body
    // to find which element was created
    if ($body.find('input').length) {
      // input was found, do something else here
      return 'input'
    }

    // else assume it was textarea
    return 'textarea'
  })
  .then((selector) => {
    // selector is a string that represents
    // the selector we could use to find it
    cy.get(selector).type(`found the element by selector ${selector}`)
  })
new2cpp
  • 3,311
  • 5
  • 28
  • 39
3

For me the following command is working for testing a VS code extension inside Code server:

Cypress.Commands.add('elementExists', (selector) => {
  return cy.window().then($window => $window.document.querySelector(selector));
});

And I'm using it like this in my E2E test for a Code Server extension:

cy.visit("http://localhost:8080");
cy.wait(10000); // just an example here, better use iframe loaded & Promise.all
cy.elementExists("a[title='Yes, I trust the authors']").then((confirmBtn) => {
    if(confirmBtn) {
        cy.wrap(confirmBtn).click();
    }
});

Just ensure that you're calling this check once everything is loaded.

If you're using Tyepscript, add the following to your global type definitions:

declare global {
  namespace Cypress {
    interface Chainable<Subject> {
      /**
       * Check if element exits
       * 
       *  @example cy.elementExists("#your-id").then($el => 'do something with the element');
       */
      elementExists(element: string): Chainable<Subject>
    }
  }
}

Aside

VS Code server relies heavily on Iframes which can be hard to test. The following blog post will give you an idea - Testing iframes with Cypress.

The above code is needed to dismiss the "trust modal" if it's shown. Once the feature disable-workspace-trust is released it could be disabled as CLI option.

AWolf
  • 8,770
  • 5
  • 33
  • 39
1

This command throws no error if element does not exist. If it does, it returns the actual element.

cypress/support/commands.js

elementExists(selector) {
  cy.get('body').then(($body) => {
    if ($body.find(selector).length) {
      return cy.get(selector)
    } else {
      // Throws no error when element not found
      assert.isOk('OK', 'Element does not exist.')
    }
  })
},

Usage:

cy.elementExists('#someSelectorId').then(($element) => {
  // your code if element exists
})
Darko Riđić
  • 459
  • 3
  • 18
1

In case somebody is looking for a way to use cy.contains to find an element and interact with it based on the result. See this post for more details about conditional testing.

Use case for me was that user is prompted with options, but when there are too many options, an extra click on a 'show more' button needs to be done before the 'desired option' could be clicked.

Command:

Cypress.Commands.add('clickElementWhenFound', (
    content: string,
) => {
    cy.contains(content)
        // prevent previous line assertion from triggering
        .should((_) => {})
        .then(($element) => {
            if (!($element || []).length) {
                /** Do something when element was not found */
            } else {
                cy.contains(content).click();
            }
        });
});

Usage:

// Click button with 'Submit' text if it exists
cy.clickElementWhenFound('Submit');
xab
  • 636
  • 7
  • 11
1

I had the same issue like button can appear in the webpage or not. I fixed it using the below code.

export function clickIfExist(element) {
cy.get('body').then((body) => {
cy.wait(5000).then(() => {
  if (body.find(element).length > 0) {
    cy.log('Element found, proceeding with test')
    cy.get(element).click()
  } else {
    cy.log('Element not found, skipping test')
  }
})
})
}
Raphael
  • 1,738
  • 2
  • 27
  • 47
0

The best way would be to check if either of two, three, etc. elements exist on a page, and decide what to do with it if it's found.

This way you can proceed with the scenario immediately without extra pausing time.

Here is working example (tested on Cypress 12.13.0):

cy.get('.deactivate-session-button, .start-work-buttons-area').then(el => {
  if (el.text() == 'End other sessions') cy.wrap(el).click()
})
cy.get('.start-work-buttons-area')

If the element was found with text "End other sessions" (it's a button) it will be clicked. If not, it means you're already logged in and can proceed to your next steps.

Hope it helps!

adam.artajew
  • 149
  • 2
  • 1
-1

Using async/await gives a clean syntax:

const $el = await cy.find("selector")
if ($el.length > 0) {
  ...

More info here: https://medium.com/@NicholasBoll/cypress-io-using-async-and-await-4034e9bab207

mikeapr4
  • 2,830
  • 16
  • 24