Skip to content

Cypress - Locators

Cypress - Modern Locators and Selector Strategies

Section titled “Cypress - Modern Locators and Selector Strategies”

Cypress primarily uses CSS selectors to identify elements on a web page, which is generally fast and reliable. While Cypress can be extended to support XPath using plugins like @cypress/xpath, CSS selectors are the recommended default. Modern best practices also emphasize using test-specific attributes like data-cy or data-testid for more resilient selectors.

Let’s explore common CSS selector patterns with an example HTML structure:

<html>
<body>
<div id="main-content">
<h1 class="title primary-heading">Welcome</h1>
<form data-cy="login-form">
<input type="email" name="email" placeholder="Enter your email" id="email-input" />
<input type="password" name="password" class="input-field password-field" />
<button type="submit" data-cy="submit-button">Login</button>
</form>
<div class="user-info">
<p>Not logged in</p>
</div>
</div>
</body>
</html>
  • By ID: cy.get('#email-input') (Selects the element with id="email-input"). Tag name is optional: input#email-input.
  • By Class: cy.get('.password-field') (Selects elements with class="password-field"). Tag name can be used: input.password-field.
  • By Attribute: cy.get('[name="email"]') (Selects elements with name="email"). Tag name can be used: input[name='email'].
  • By Test-Specific Attribute (Best Practice): cy.get('[data-cy="submit-button"]') (Selects the element with data-cy="submit-button"). This is highly recommended as it decouples tests from CSS or JS changes.
  • By Tag Name: cy.get('button') (Selects all <button> elements. Use with caution, be specific).
  • Parent-Child Traversal: cy.get('form[data-cy="login-form"] input[name="email"]') (Selects the email input within the login form). Or using Cypress commands: cy.get('[data-cy="login-form"]').find('input[name="email"]').
  • Chaining Traversals: cy.get('#main-content').children('.user-info').find('p') (Finds the paragraph within .user-info which is a child of #main-content).

cy.contains() is useful for selecting elements based on their text content. It can take a selector as an optional first argument to narrow down the search.

// Finds any element containing 'Welcome'
cy.contains('Welcome');
// Finds a button containing 'Login'
cy.contains('button', 'Login');
// Finds an element with data-cy='submit-button' that contains 'Login'
cy.contains('[data-cy="submit-button"]', 'Login');

Cypress Test Runner includes a ‘Selector Playground’ feature. This interactive tool helps you determine unique selectors for elements by simply clicking on them in your application preview. It often provides the best cy.get() command with an appropriate selector.

To use it:

  1. Open the Cypress Test Runner.
  2. Run a test or open your application via cy.visit().
  3. Click the ‘target’ icon (Open Selector Playground) in the Test Runner header.
  4. Hover over and click on elements in your application preview.
  5. Cypress will suggest a selector in the cy.get() field. You can copy this directly into your test code.

While the Selector Playground is helpful, always review its suggestions and consider if a more robust selector (like a data-cy attribute) is more appropriate for long-term test stability.

If CSS selectors are not sufficient for a particular case (e.g., finding elements based on complex relationships or text content not easily handled by cy.contains()), you can use XPath via the @cypress/xpath plugin.

  1. Install the plugin: npm install -D @cypress/xpath or yarn add -D @cypress/xpath.

  2. Add require('@cypress/xpath') to your cypress/support/e2e.js file (or cypress/support/commands.js if you use that structure).

Then you can use cy.xpath('//your/xpath/expression') in your tests.

Example: cy.xpath('//button[contains(text(), "Submit")]')

Further Reading: