How to check if element exists using Cypress.io [duplicate]
Asked Answered
S

12

93

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

Smetana answered 15/5, 2019 at 9:27 Comment(4)
Does this answer your question? How to check for an element that may not exist using CypressTaction
How come you close this popular question as duplicate, 4.5 years after its being asked?Smetana
"Possible duplicate" is a way to clean-up - to close similar questions and keep one with the best answers. The date is not essential. See should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer If you agree that it requires clarification please vote on add-clarification-link-to-possible-duplicate-automated-commentTaction
See also: https://mcmap.net/q/225755/-how-to-check-for-an-element-that-may-not-exist-using-cypress for cypress-ifSpieler
A
8

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...
    })
Alys answered 18/4, 2020 at 6:35 Comment(0)
R
132

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

Recti answered 15/5, 2019 at 14:34 Comment(8)
thanks @Recti This should be the correct answer.Dampier
Thanks, buddy! This is a working solution. this should be the accepted answer.Distributive
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).Argentum
The if statement .length does not work any morePuncheon
@AshokkumarGanesan works for me since long time :) and still this is a good solutionKenton
@AshokkumarGanesan It doesn't work for me too. Did you find another solution?Fortitude
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( <find with $body tag>) you have also done the same. Can you please explain why your solution is correct?Atomics
This solution has a .length > 0 as opposed to just checking for the property itself.Lament
C
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})
        }
    })
Chloroprene answered 15/5, 2019 at 9:52 Comment(0)
A
8

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...
    })
Alys answered 18/4, 2020 at 6:35 Comment(0)
N
7

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)
    });
})
Neslund answered 2/9, 2021 at 14:53 Comment(2)
Failed to execute 'querySelector' on 'Document': '[object Object]' is not a valid selector.Twin
This solution is the one that works, I've tried the other ones but none of them worksNoeminoesis
F
4

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}`)
  })
Fabricate answered 30/7, 2022 at 18:7 Comment(0)
K
4

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.

Kiarakibble answered 23/10, 2022 at 14:34 Comment(0)
P
2

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
})
Pascual answered 20/7, 2022 at 4:32 Comment(1)
That's not how you write a custom command, if that's your intention.Mckelvey
G
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');
Gunnar answered 7/11, 2022 at 17:52 Comment(1)
Your URL is brokenHubbell
A
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')
  }
})
})
}
Annihilator answered 8/2, 2023 at 13:29 Comment(0)
P
1

This solution worked for me:

cy.get('body').then($body => {
    if ($body.find("mat-option[aria-selected='true']").length) {
        //Do something if exist
    }
    else{
        //do if not exist
    }
})
Pintail answered 28/11, 2023 at 7:42 Comment(0)
A
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!

Appressed answered 30/5, 2023 at 16:57 Comment(0)
A
-3

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

Allowedly answered 5/11, 2020 at 13:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.