Discovering if an element is present with Cypress.io

Is there a straightforward way to determine if an element is present, and then proceed with specific steps based on its presence or absence?

I attempted the following approach, but it did not yield the desired results:

Cypress.Commands.add('deleteSomethingFunction', () => {
  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 seeking a simple solution that can be easily incorporated using basic JavaScript syntax like an if-else block or the then() section of a Promise.

Something akin to the following implementations from the Webdriver protocol:

  1. driver.findElements(By.yourLocator).size() > 0
  2. Check for element presence during a wait operation

Your advice would be greatly appreciated. Thank you.

Answer №1

It's important to remember that when using the .length property of the cy.find command in an if condition, you must consider Cypress's asynchronous nature.

For example: The following condition may evaluate as false even if the appDrawerOpener button exists

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

However, this condition will evaluate as true because the $body variable is already resolved within a .then() block:

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

For more information, refer to the Cypress documentation on conditional testing

Answer №2

There has been previous speculation: Conditional statement in Cypress

Therefore, one possible approach is:

cy.get('header').then(($element) => { 
        if ($element.text().includes('Account')) {
            cy.contains('Account')
            .click({force:true})
        } else if ($element.text().includes('Sign')) { 
            cy.contains('Sign In')
            .click({force:true})  
        } else {
            cy.get('.navUser-item--account .navUser-action').click({force:true})
        }
    })

Answer №3

When working with Cypress, it's important to remember that all steps are asynchronous. To handle this efficiently, consider creating a common function either in the commands file or page object file.

export function checkIfElementExists(element){
    return new Promise((resolve,reject)=>{
        cy.get('body').find(element).its('length').then(result=>{
            if(result > 0){
                cy.get(element).select('100').wait(2000);
                resolve();
            }else{
                reject();
            }
        });
    })
}

// Example usage: checking if select[aria-label="rows per page"] exists
cy.checkIfElementExists('select[aria-label="rows per page"]')
.then(()=>{
    //// Perform tasks if the element exists
})
.catch(()=>{
    //// Handle case where the element does not exist
})

Answer №4

Here is a helpful solution I discovered:

Try implementing the following code snippet:

cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('The value of the object is: ' + identifiedElement)
    });

You can integrate this into your commands.js file within Cypress:

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

    cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('The value of the object is: ' + identifiedElement)
    });
})

Answer №5

A solution to the specific issue has been provided in the official Cypress documentation.

Guidelines on verifying Element existence

// To make new elements appear,
// click on the button
cy.get('button').click()
cy.get('body')
  .then(($body) => {
    // Search within the body synchronously
    // for the created element
    if ($body.find('input').length) {
      // Take action if input is found
      return 'input'
    }

    // If not an input, then assume it's a textarea
    return 'textarea'
  })
  .then((selector) => {
    // Use the retrieved selector string
    // to locate and interact with the element
    cy.get(selector).type(`Located element using selector ${selector}`)
  })

Answer №6

When testing a VS Code extension in Code server, I found that the following command worked for me:

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

In my E2E test for a Code Server extension, I use it like this:

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();
    }
});

Make sure to call this check after everything is loaded.

If you're using TypeScript, 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 heavily relies on Iframes which can be challenging to test. Check out this blog post for more information - Testing iframes with Cypress.

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

Answer №7

This function does not generate an error if the specified element is missing. Instead, it will return the element itself.

File Path: cypress/support/commands.js

checkElement(selector) {
  cy.get('body').then(($body) => {
    if ($body.find(selector).length) {
      return cy.get(selector)
    } else {
      // No error thrown for missing element
      assert.isOk('OK', 'Element does not exist.')
    }
  })
},

How to Use:

cy.checkElement('#someSelectorId').then(($element) => {
  // Your code goes here if the element exists
})

Answer №8

Experiencing a similar issue with the visibility of the like button on a webpage, I managed to resolve it by implementing the following code snippet.

function clickIfButtonExists(btn) {
  cy.get('body').then((body) => {
    cy.wait(5000).then(() => {
      if (body.find(btn).length > 0) {
        cy.log('Button found, test will proceed')
        cy.get(btn).click()
      } else {
        cy.log('Button not found, skipping test')
      }
    })
  })
}

Answer №9

If someone is searching for a way to utilize the cy.contains function to locate an element and interact with it based on the outcome, they can refer to this article for more insights on conditional testing.

I encountered a scenario where users are presented with multiple options, requiring an additional click on a 'show more' button before accessing their desired choice.

Action:

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

Example:

// Click on the button with 'Submit' text if it exists
cy.clickElementWhenFound('Submit');

Answer №10

I found success with the following method:

cy.get('body').then($body => {
    if ($body.find("mat-option[aria-selected='true']").length) {
        //Perform actions if element exists
    }
    else{
        //Perform actions if element does not exist
    }
})

Answer №11

The most effective approach is to check for the presence of multiple elements on a web page and take action accordingly once they are found.

This method allows you to continue with the process without any unnecessary pauses in between.

Below is an example that has been successfully 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 containing the text "End other sessions" (a button) is located, it will be clicked. Otherwise, it indicates that you are already logged in and can proceed with your next steps.

I trust this information proves useful to you!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Select each item in the list one by one

Is it possible to click on each element individually in a list with the following locator format: id=${NameFirst.replace(" ", ""}_${NameLast.replace(" ", "")} *Keywords* | Obtain all first and last names | | ${Name} | Search Master Database ...

Keeping firebase auth while removing firestore from Vue project

I have recently made the switch from Firestore to MongoDB, and I am currently in the process of removing references to Firestore in my App.vue file. However, I am still utilizing Firebase authentication. Upon checking the console error message, I came acr ...

Ways to troubleshoot the issue of "The webdriver.chrome.driver system property must be set to the driver executable path" error

package excelprog.TestDDT; import org.testng.annotations.Test; import TestUtil.TestUtil; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.open ...

How to access webpack's require.context feature on the development server

In my webpack development configuration, I have set up a mocked backend using Express. Following an example from the DevServer Docs, my setup looks something like this: module.exports = { // ... devServer: { setupMiddlewares: (middlewares, devServe ...

Learn how to retrieve values from a .json file in real-time and then perform comparisons with user input using Python

I have a JSON file structured like this: [ { "name": { "common": "Aruba", "official": "Aruba", "native": { "nld": { "official ...

Managing state in React for a nested object while still maintaining the data type of the

Exploring the question further from this particular query Updating State in React for Nested Objects The process of updating nested state involves breaking down the object and reconstructing it as shown below: this.setState({ someProperty: { ...this.stat ...

Is AngularJS Experiencing Bugs with the Webcam getUserMedia API?

I recently created a webcam directive in AngularJS that utilizes a service. For reference, I followed this example: Surprisingly, the example works perfectly on my tablet, but when I integrate the code into my tablet's Google Chrome browser, it encou ...

Application of Criteria for Zod Depending on Data Stored in Array Field

I am currently working on an Express route that requires validation of the request body using Zod. The challenge arises when I need to conditionally require certain fields based on the values in the "channels" field, which is an array of enums. While my cu ...

Keep moving the box back and forth by pressing the left and right buttons continuously

Looking to continuously move the .popup class left and right by clicking buttons for left and right movement. Here is the js fiddle link for reference. This is the HTML code structure: <button class="right">Right</button> <button class="l ...

React.js: The function useDef has not been defined

Attempting to create a React.js calculator application, my initial step was to delete the entire src folder and replace it with a new one containing the necessary elements for the web app. Here is the content of the index.js file: import React,{ useEffect, ...

Is it conceivable to exploit JSON responses with appropriate JavaScript string escaping to launch an XSS attack?

Exploiting JSON responses can occur when Array constructors are overridden or when hostile values are not properly JavaScript string-escaped. To combat this, Google has implemented a technique where all JSON responses are prefixed with a specific code sni ...

Trigger function in a different child component on mouse up

Trying to call a function in a child component from another child component in ReactJS. Specifically, I want to trigger a function in another component when the 'mouseup' event happens. Here is an illustration of what I am attempting to achieve: ...

What is the process of generating enum values using ES6 in Node.js?

Can JavaScript support enumerations with assigned integer values, similar to how other programming languages handle it? In C#, for instance, I can define an enum as follows: enum WeekDays { Monday = 0, Tuesday =1, Wednesday = 2, Thursday ...

Ways to guide users through a single-page website using the URL bar

I currently have a one-page website with links like <a href="#block1">link1</a>. When clicked, the browser address bar displays site.com/#block1 I am looking to modify this so that the browser shows site.com/block1, and when the link is clicke ...

Issue with undefined bindingContext.$data in IE9 on knockout binding handler

I'm attempting to create a unique binding handler that applies role-based access to fields on a page. This custom handler uses the values of other observables from the viewModel to enable or disable input controls based on certain conditions. However ...

A guide on updating data with duplicate values in Knex

Suppose I have the following array of data: const customerIds = [ '7d8206d2-74bc-4b90-a237-37f92486cde4', 'e594fe7f-d529-4a2f-ab24-ffc4e102268c', '7d8206d2-74bc-4b90-a237-37f92486cde4' ] As seen, there are duplicate IDs ...

Sending a batch of files through an axios request by passing them as an object

I need to send multiple images in a specific format through an API call { "date":"currentDate", "files":[Files uploaded via input box] } Here is my approach: Method 1 const event = document.querySelector("#files"); const f ...

Guide to importing an AngularJS controller into an Express file (routes.js)

Currently, I am in the process of developing a restful service and my goal is to organize my callbacks within controllers in order to avoid cluttering my routes.js file. Previously, I had been using controller = require(path.to.controller); This enabled ...

What is the best practice for adding a DOM element at a precise location within an ng-repeat loop?

I am currently working on developing a podcast player application using AngularJS. At this point, I have successfully created a list of available podcasts that can be played, utilizing ng-repeat. The code for the list is shown below: <ul ng-controller ...

Transitioning a JavaScriptIonicAngular 1 application to TypescriptIonic 2Angular 2 application

I am currently in the process of transitioning an App from JavaScript\Ionic\Angular1 to Typescript\Ionic2\Angular2 one file at a time. I have extensively researched various guides on migrating between these technologies, completed the A ...