Aliasing

Examples of referencing DOM elements or resources for later use in Cypress, for a full reference of commands, go to docs.cypress.ioopen in new window

.as

Alias a DOM element

<table class="as-table table table-bordered">
  <thead>
    <tr>
      <th>Column 1</th>
      <th>Column 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        Row 1: Cell 1
        <button class="btn btn-primary">Change</button>
      </td>
      <td>
        Row 1: Cell 2
        <button class="btn btn-primary">Change</button>
      </td>
    </tr>
    <tr>
      <td>
        Row 2: Cell 1
        <button class="btn btn-primary">Change</button>
      </td>
      <td>
        Row 2: Cell 2
        <button class="btn btn-primary">Change</button>
      </td>
    </tr>
  </tbody>
</table>
<script>
  $('.as-table .btn').on('click', function (e) {
    e.preventDefault()
    $(e.currentTarget).addClass('btn-success').text('Changed')
  })
</script>
// Alias a DOM element for use later
// We don't have to traverse to the element
// later in our code, we reference it with @

cy.get('.as-table')
  .find('tbody>tr')
  .first()
  .find('td')
  .first()
  .find('button')
  .as('firstBtn')

// when we reference the alias, we place an
// @ in front of its name
cy.get('@firstBtn').click()

cy.get('@firstBtn')
  .should('have.class', 'btn-success')
  .and('contain', 'Changed')

List example

Another example of aliasing a DOM element

<ul data-cy="query-the-alias">
  <li>Apple</li>
  <li>Banana</li>
  <li>Grape</li>
</ul>
cy.get('[data-cy=query-the-alias]').as('fruits')
// now we can use cy.get to grab the DOM element
cy.get('@fruits')
  .should('have.prop', 'tagName', 'UL')
  .and('be.visible')
// find child elements
cy.get('@fruits').find('li').should('have.length', 3)
cy.get('@fruits').contains('li', 'Banana')
cy.get('@fruits').contains('li', 'Grape')

Note: if all the assertions related to the DOM elements are grouped together, it is simpler to use cy.withinopen in new window command.

cy.log('**equivalent code using cy.within**')
cy.get('[data-cy=query-the-alias]').within(() => {
  cy.root()
    .should('have.prop', 'tagName', 'UL')
    .and('be.visible')
  cy.get('li').should('have.length', 3)
  cy.contains('li', 'Banana')
  cy.contains('li', 'Grape')
})

Alias a network route

<button class="network-btn btn btn-primary">Get Comment</button>
<div class="network-comment"></div>
<script>
  function getComment() {
    // we fetch all data from this REST json backend
    const root = 'https://jsonplaceholder.cypress.io'
    $.ajax({
      url: `${root}/comments/1`,
      method: 'GET',
    }).then(function (data) {
      $('.network-comment').text(data.body)
    })
  }
  $('.network-btn').on('click', function (e) {
    e.preventDefault()
    getComment(e)
  })
</script>
// Alias the route to wait for its response
cy.intercept('GET', 'comments/*').as('getComment')

// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click()

// https://on.cypress.io/wait
cy.wait('@getComment')
  .its('response.statusCode')
  .should('eq', 200)

Alias values

<button data-cy="magic-number">42</button>
// retrieve the element's text and convert into a number
cy.get('[data-cy=magic-number]')
  .invoke('text')
  .then(parseInt)
  .as('magicNumber')
// saved the value 42 under an alias
// retrieve it some time later
cy.get('@magicNumber').should('equal', 42)

Test context

The aliased values are set as properties in the test context object. You can retrieve them later using this.alias syntax if you use the function () {...} callback syntax.

Let's confirm the two list items have different text.

<ul data-cy="test-context">
  <li>Purple</li>
  <li>Orange</li>
</ul>
cy.get('[data-cy=test-context] li')
  .first()
  .invoke('text')
  .as('first')
cy.get('[data-cy=test-context] li')
  .eq(1)
  .invoke('text')
  .as('second')
  .then(function () {
    // by the time this callback runs
    // both "first" and "second" properties are set
    // notice the "function () {...}" syntax
    // to get the "this" to point at the test context object
    expect(this.first)
      .to.equal('Purple') // sanity check
      .and.not.equal(this.second)
  })

Alternatively, we could have used .then callbacks to get a "pyramid of Doom"

cy.log('**using callbacks**')
cy.get('[data-cy=test-context] li')
  .first()
  .invoke('text')
  .then((first) => {
    cy.get('[data-cy=test-context] li')
      .eq(1)
      .invoke('text')
      .then((second) => {
        expect(first)
          .to.equal('Purple') // sanity check
          .and.not.equal(second)
      })
  })

Finally, we could have used local variables

let first, second
cy.log('**using variables**')
cy.get('[data-cy=test-context] li')
  .first()
  .invoke('text')
  .then((x) => (first = x))

cy.get('[data-cy=test-context] li')
  .eq(1)
  .invoke('text')
  .then((x) => (second = x))

// by the time this callback runs, both local
// variables are set
cy.then((second) => {
  expect(first)
    .to.equal('Purple') // sanity check
    .and.not.equal(second)
})

static vs query type

Cypress v12 has introduced chains of queriesopen in new window that are automatically retried. This has affected the behavior of the .as command. Imagine we have the following HTML snippet and the test confirming the text on the button.

📺 Watch this example explained in the video Cypress cy.as Alias Types: Query vs Staticopen in new window.

<button id="click">Loading...</button>
<script>
  setTimeout(() => {
    document.getElementById('click').innerText = 'Profile'
  }, 1000)
</script>
cy.get('#click').invoke('text').invoke('trim').as('caption')

Let's get the alias caption and confirm it becomes "Profile".

cy.get('@caption').should('equal', 'Profile')

This means the aliased value changes. The last code line is really equivalent to:

// The last line that uses the alias
cy.get('@caption').should('equal', 'Profile')
// is equivalent to this code with the alias
// replaced by the query commands leading to the ".as(...)"
cy.get('#click')
  .invoke('text')
  .invoke('trim')
  .should('equal', 'Profile')

This behavior is different from the aliases before Cypress v12. If you want to save the aliased value once and never re-evaluate it again, use the parameter type: static.

<button id="click">Loading...</button>
<script>
  setTimeout(() => {
    document.getElementById('click').innerText = 'Profile'
  }, 1000)
</script>
cy.get('#click')
  .invoke('text')
  .invoke('trim')
  .as('caption', { type: 'static' })

Let's wait 1.5 seconds and confirm the alias still remains "Loading...", while the button has already changed its text

// the button has changed its text
cy.contains('#click', 'Profile')
// but the aliased value remains the same
cy.get('@caption').should('equal', 'Loading...')