# Querying

Examples of querying for DOM elements in Cypress, for a full reference of commands, go to docs.cypress.io and read Selecting Elements: Best Practices Guide

# cy.get()

To query for the button, use the cy.get() command.

<div id="querying-example">
  <div class="well">
    <button id="query-btn" class="query-btn btn btn-primary">
      Button
    </button>
  </div>
</div>
// selects the button using ID
cy.get('#query-btn').should('contain', 'Button')
// selects the button using class
cy.get('.query-btn').should('contain', 'Button')

// Use CSS selectors just like jQuery
cy.get('#querying-example .well>button:first').should(
  'contain',
  'Button',
)

# Number of items

You can attach an assertion to confirm the number of elements.

<section>
  <h4>Example</h4>
  <h5>Querying elements</h5>
  <p>This page has heading elements</p>
  <h6>cy.get</h6>
</section>

Example

Querying elements

This page has heading elements

cy.get
// find all H4 + H5 + H6 elements
// and confirm the minimum number of elements
// using the "greater" assertion
cy.get('h4,h5,h6').should('have.length.gt', 1)

Tip: use the .should('have.length', N) assertion to confirm the exact number of elements. For example, see Assertions page.

# jQuery selectors

cy.get uses jQuery selectors, thus you can immediately use them to find elements by text (or without given text).

<table>
  <tbody>
    <tr>
      <td>Same</td>
      <td>Same</td>
      <td>Different</td>
      <td>Same</td>
    </tr>
  </tbody>
</table>
Same Same Different Same
// selects all table cells with text "Same"
cy.get('td:contains("Same")').should('have.length', 3)
// if the text does not have white spaces, no need to quote it
cy.get('td:contains(Same)').should('have.length', 3)
// you can find elements NOT having the given text
cy.get('td:not(:contains(Same))')
  .should('have.length', 1)
  .and('have.text', 'Different')

# Escaping special characters

If the element's selector has special characters like . or : escape the using \\ character

<div id="user:1234" class="admin.user">Joe</div>
Joe
cy.get('#user\\:1234').should('have.text', 'Joe')
cy.get('.admin\\.user')
  // no need to escape the non-selector text
  .should('have.id', 'user:1234')

# Using attribute selector

You can grab all elements that have an attribute present. For example, to find all <LI> rows with an attribute "line" present:

<ul id="row-attributes">
  <li>No line</li>
  <li>No line</li>
  <!-- attribute line has no value at all -->
  <li line>line</li>
  <li line="up">line</li>
  <li line="down">line</li>
  <li>No line</li>
</ul>
  • No line
  • No line
  • line
  • line
  • line
  • No line
cy.get('#row-attributes li[line]').should('have.length', 3)

You can grab elements with a given attribute. For example, let's make sure there is only a single <a> element pointing at "index.html":

<a href="article1.html">Article 1</a>
<a href="article2.html">Article 2</a>
<a href="article3.html">Article 3</a>
<a href="index.html">index</a>
cy.get('a[href="index.html"]').should('have.length', 1)

# Attribute prefix

Let's get the element with ID starting with "local-example" prefix

<ul>
  <li id="local-example-123">first</li>
  <li id="remote-example-456">second</li>
</ul>
  • first
  • second
cy.get('[id^=local-example]').should('have.text', 'first')

# Attribute suffix

Let's get the element with ID ending with "example-AF9" string

<ul>
  <li id="this-example-ZFX">first</li>
  <li id="that-example-AF9">second</li>
</ul>
  • first
  • second
cy.get('[id$=example-AF9]').should('have.text', 'second')

# Combining attribute selectors

Let's get the element with ID that starts with "my-" prefix and ending with "-yours" suffix

<ul>
  <li id="my-first-123">first</li>
  <li id="my-second-yours">second</li>
</ul>
  • first
  • second
cy.get('[id^=my-][id$=-yours]').should('have.text', 'second')

# Using data attribute

To find elements by data attribute, query using the attribute selector.

<div data-test-id="test-example" class="example">
  Div with <code>data-test-id</code>
</div>
Div with data-test-id
cy.get('[data-test-id="test-example"]').should(
  'have.class',
  'example',
)

cy.get() yields a jQuery object, you can get its attribute by invoking the .attr() method.

// find the element, confirm its attribute
cy.get('[data-test-id="test-example"]')
  .invoke('attr', 'data-test-id')
  .should('equal', 'test-example')

// or you can get an element's CSS property
cy.get('[data-test-id="test-example"]')
  .invoke('css', 'position')
  .should('equal', 'static')

Alternatively, chain assertions directly to the cy.get() call. See assertions documentation.

cy.get('[data-test-id="test-example"]')
  .should('have.attr', 'data-test-id', 'test-example')
  .and('have.css', 'position', 'static')

# cy.contains()

We can find elements by their content using cy.contains()

<div id="querying">
  <ul class="query-list">
    <li class="first">apples</li>
    <li class="second">oranges</li>
    <li class="third">bananas</li>
    <li class="fourth">more apples</li>
  </ul>
  <div class="query-button">
    <button class="btn btn-default">
      <span>Save Form</span>
    </button>
  </div>
</div>
  • apples
  • oranges
  • bananas
  • more apples
cy.get('.query-list')
  .contains('bananas')
  .should('have.class', 'third')

// we can pass a regexp to `.contains()`
cy.get('.query-list').contains(/^b\w+/).should('have.class', 'third')

cy.get('.query-list').contains('apples').should('have.class', 'first')

// passing a selector to contains will
// yield the selector containing the text
cy.get('div#querying')
  .contains('ul', 'oranges')
  .should('have.class', 'query-list')

cy.get('.query-button')
  .contains('Save Form')
  .should('have.class', 'btn')

# .within

We can find elements within a specific DOM element .within()

<h6>Name input</h6>
<input
  type="text"
  id="inputName"
  class="form-control"
  placeholder="Name"
/>
<h6>Form</h6>
<form class="query-form">
  <input
    type="text"
    id="inputEmail"
    class="form-control"
    placeholder="Email"
  />
  <input
    type="text"
    id="inputPassword"
    class="form-control"
    placeholder="Password"
  />
</form>
Name input
Form
// validate placeholder attributes
cy.get('.query-form').within(() => {
  cy.get('input:first').should('have.attr', 'placeholder', 'Email')
  cy.get('input:last').should('have.attr', 'placeholder', 'Password')
})

# Yields the original element

The cy.within yields the same DOM element it received as the parent.

<div id="within-yields">
  The parent div
  <div class="some-child">Child element</div>
</div>
The parent div
Child element
cy.get('#within-yields')
  .within(() => {
    // we are trying to return something
    // from the .within callback,
    // but it won't have any effect
    return cy
      .contains('Child element')
      .should('have.class', 'some-child')
  })
  .should('have.id', 'within-yields')

You can attempt to cy.wrap a different value - still the original parent element is going to be yielded.

<div id="wrap-inside-within">
  The parent div
  <div class="some-child">Child element</div>
</div>
The parent div
Child element
cy.get('#wrap-inside-within')
  .within(() => {
    // returning cy.wrap(...) has no effect on the yielded value
    // it will still be the original parent DOM element
    return cy.wrap('a new value')
  })
  .should('have.id', 'wrap-inside-within')

# Temporarily escape .within

You can temporarily escape the .within scope by using cy.root + cy.closest commands.

<section id="escape-example">
  <h6>Name input</h6>
  <input
    type="text"
    id="inputName"
    class="form-control"
    placeholder="Name"
  />
  <h6>Form</h6>
  <form class="the-form">
    <input
      type="text"
      id="inputEmail"
      class="form-control"
      placeholder="Email"
    />
    <input
      type="text"
      id="inputPassword"
      class="form-control"
      placeholder="Password"
    />
  </form>
</section>
Name input
Form
cy.get('.the-form').within(() => {
  // escape back find H6
  cy.root().closest('#escape-example').contains('h6', 'Name input')
  // escape and enter text into the input field
  cy.root()
    .closest('#escape-example')
    .find('input#inputName')
    .type('Batman')
})

Note: you need the cy.root() command first because cy.closest is a child command and cannot be used to start the new command chain.

# Number of elements

Using .within followed by cy.get is convenient for finding multiple matching elements inside another element. For example, let's confirm that the given picture element has at least 2 source elements and 1 img child element.

<picture>
  <source srcset="logo-768.png 768w, logo-768-1.5x.png 1.5x" />
  <source srcset="logo-480.png, logo-480-2x.png 2x" />
  <img src="logo-320.png" alt="logo" />
</picture>
logo
cy.get('picture').within(() => {
  // at least 2 source elements
  cy.get('source').should('have.length.gt', 1)
  // single img element
  cy.get('img').should('have.length', 1)
})

# Within works with multiple elements

The parent command can yield multiple elements.

<ul id="fruits">
  <li id="item-apples"><a href="/apples">Apples</a></li>
  <li id="item-oranges"><a href="/oranges">Oranges</a></li>
</ul>
cy.get('#fruits li').within(() => {
  cy.root().should('have.length', 2) // there are 2 LI items
  cy.contains('a', 'Apples').should('have.attr', 'href', '/apples')
  cy.contains('a', 'Oranges').should('have.attr', 'href', '/oranges')
})

# cy.root()

We can find the root DOM element cy.root()

<ul class="query-ul">
  <li>One</li>
  <li>Two</li>
  <li>Buckle my shoe</li>
</ul>
  • One
  • Two
  • Buckle my shoe
// By default, root is the document
cy.root().should('match', 'html')

cy.get('.query-ul').within(() => {
  // In this within, the root is now the ul DOM element
  cy.root().should('have.class', 'query-ul')
})

# Best Practices: Selecting elements

Prefer dedicated data-cy or data-test attributes to CSS class names and element IDs. See detailed discussion at Best Practices: Selecting elements

<div id="best-practices">
  <button
    id="main"
    class="btn btn-large"
    name="submission"
    role="button"
    data-cy="submit"
  >
    Submit
  </button>
</div>
cy.get('#best-practices').within(() => {
  // Worst - too generic, no context
  cy.get('button').click()

  // Bad. Coupled to styling. Highly subject to change.
  cy.get('.btn.btn-large').click()

  // Average. Coupled to the `name` attribute which has HTML semantics.
  cy.get('[name=submission]').click()

  // Better. But still coupled to styling or JS event listeners.
  cy.get('#main').click()

  // Slightly better. Uses an ID but also ensures the element
  // has an ARIA role attribute
  cy.get('#main[role=button]').click()

  // Much better. But still coupled to text content that may change.
  cy.contains('Submit').click()

  // Best. Insulated from all changes.
  cy.get('[data-cy=submit]').click()
})

# cy.get vs .find

The cy.get command always starts its search from the document element, or, if used inside .within, from the cy.root element. The .find command starts the search from the current subject.

<div class="test-title">cy.get vs .find</div>
<section id="comparison">
  <div class="feature">Both are querying commands</div>
</section>
cy.get vs .find
Both are querying commands
cy.get('#comparison')
  .get('div')
  // finds the DIV .test-title outside the #parent
  // and the DIV .feature inside
  .should('have.class', 'test-title')
  .and('have.class', 'feature')
cy.get('#comparison')
  .find('div')
  // the search is limited to the tree at #comparison element
  .should('have.length', 1)
  .and('have.class', 'feature')