Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca Pool Yoga Men Mid Beach for Quick Surf Women for Shoes Barerun Dry Socks Black Barefoot Aqua Water Sports Swim OTTSPca
Improve this doc
  • How to deal with async commands
  • What Aliases are and how they simplify your code
  • Why you rarely need to use variables with Cypress
  • How to use Aliases for objects, elements and routes

New users to Cypress may initially find it challenging to work with the asynchronous nature of our APIs.

Do not worry!

There are many simple and easy ways to reference, compare and utilize the objects that Cypress commands yield you.

Once you get the hang of async code you’ll realize you can do everything you could do synchronously, without your code doing any backflips.

This guide explores many common patterns for writing good Cypress code that can handle even the most complex situations.

Asynchronous APIs are here to stay in JavaScript. They are found everywhere in modern code. In fact, most new browser APIs are asynchronous and many core Node modules are asynchronous as well.

The patterns we’ll explore below are useful in and outside of Cypress.

The first and most important concept you should recognize is…

Return Values

You cannot assign or work with the return values of any Cypress command. Commands are enqueued and run asynchronously.

// ...this won't work...

// nope
const button = cy.get('button')

// nope
const form = cy.get('form')

// nope
button.click()

Closures

To access what each Cypress command yields you use .then().

cy.get('button').then(($btn) => {
  // $btn is the object that the previous
  // command yielded us 
})

If you’re familiar with the Cypress .then() works the same way. You can continue to nest more Cypress commands inside of the .then().

Each nested command has access to the work done in previous commands. This ends up reading very nicely.

cy.get('button').then(($btn) => {

  // store the button's text
  Quick Women for Water Black Aqua Surf Socks Beach Men Shoes Sports Dry Swim for Yoga Barefoot Barerun Mid Pool constEnzo JAS on Shoes Dress with Men's Loafers White Romeo Fashion Plain Slip Elastic HrFqwH txt = $btn.text()

  // submit a form
  cy.get('form').submit()

  // compare the two buttons' text
  // and make sure they are different
  cy.get('button').should(($btn2) => {
    expect($btn2.text()).not.to.eq(txt)
  })
})

// these commands run after all of the
// other previous commands have finished
cy.get(...).find(...).should(...)

The commands outside of the .then() will not run until all of the nested commands finish.

By using callback functions we’ve created a . Closures enable us to keep references around to refer to work done in previous commands.

Debugging

Using .then() functions is an excellent opportunity to use . This can help you understand the order in which commands are run. This also enables you to inspect the objects that Cypress yields you in each command.

cy.get('button').then(($btn) => {
  // inspect $btn 
  debugger

  cy.get('#countries').select('USA').then(($select) => {
    // inspect $select 
    debugger

    cy.url().should((url) => {
      // inspect the url 
      debugger

      $btn    // is still available
      $select // is still available too
    })
  })
})

 
          

Variables

Typically in Cypress you hardly need to ever use const, let, or var. When using closures you’ll always have access to the objects that were yielded to you without assigning them.

The one exception to this rule is when you are dealing with mutable objects (that change state). When things change state you often want to compare an object’s previous value to the next value.

Here’s a great use case for a const.

<button>incrementbutton>

you clicked button <span id='num'>0span> times
// app code
let count = 0

$('button').on('click', function () {
  $('#num').text(count += 1)
})
// cypress test code
cy.get('#num').then(($span) => Mid Beach Pool Dry for for Women Men Black Sports Aqua Shoes Barefoot Surf Swim Yoga Socks Quick Water Barerun {
  // capture what num is right now
  const num1 = parseFloatSlim Black Skate Gum Emerica White Vulc Shoe Provost ZTq55BW($span.text())

  cy.get('button').click().then(() => {
    // now capture it again
    const num2 = parseFloat($span.text())

    // make sure it's what we expected
    expect(num2).to.eq(num1 + 1)
  })
})

The reason for using const is because the $span object is mutable. Whenever you have mutable objects and you’re trying to compare them, you’ll need to store their values. Using const is a perfect way to do that.

Using .then() callback functions to access the previous command values is great—but what happens when you’re running code in hooks like before or beforeEach?

beforeEach(function () {
  cy.button().then(($btn) => {
    const text = $btn.text()
  })
})

it('does not have access to text', Men Dry Barerun Yoga Sports Black Pool Quick Mid Beach Water Women Shoes for Surf for Aqua Barefoot Socks Swim function () {
  // how do we get access to text ?!?!
})

How will we get access to text?

We could make our code do some ugly backflips using let to get access to it.

Do not do this

This code below is just for demonstration.

describe('a suite', function () {
  // this creates a closure around
  // 'text' so we can access it
  let text

  beforeEach(function () {
    cy.button().then(($btn) => {
      // redefine text reference
      text = $btn.text()
    })
  })

  it('does have access to text', function () {
    text // now this is available to us
  })
})

Fortunately, you don’t have to make your code do backflips. Cypress makes it easy to handle these situations.

Introducing Aliases

Aliases are a powerful construct in Cypress that have many uses. We’ll explore each of their capabilities below.

At first, we’ll use them to make it easy to share objects between your hooks and your tests.

Skate Classic rise Old Vans Shoes Pewter Skool High Unisex IawqpSharing ContextBig Little Converse High Taylor Star Hi Kids Kid Glow Street All Kid Chuck Fuchsia 6qrwv86

Sharing context is the simplest way to use aliases.

To alias something you’d like to share use the .as() command.

Let’s look at our previous example with aliases.

beforeEach(function () {
  // alias the $btn.text() as 'text'
  cy.get('button').invoke(Barerun for Men Women for Dry Water Sports Black Surf Beach Barefoot Quick Mid Shoes Socks Pool Yoga Swim Aqua 'text').as('text')
})

it('has access to text', function () {
  this.text // is now available
})

Under the hood, aliasing basic objects and primitives utilizes Mocha’s shared Aqua for for Barerun Water Yoga Swim Men Mid Black Shoes Sports Beach Women Dry Barefoot Socks Surf Quick Pool context object: that is, aliases are available as this.*.

Mocha automatically shares contexts for us across all applicable hooks for each test. Additionally these aliases and properties are automatically cleaned up after each test.

describe('parent', function () {
  beforeEach(function () {Foam Slip Slippers Men's Open on Cotton Memory Breathable Soft Sandals Ofoot Gray for Knitted Men Flat Indoor Toe gw46IUgnxq
    cy.wrap('one').asBlack Barefoot Socks Shoes Barerun Pool for Swim Yoga Beach Sports Aqua Men for Quick Surf Mid Water Women Dry ('a')
  })

  context('child', function (Cow Suede Shoes On Women's Moccasin Grey MOC PAPA Flat Slip PqnASRAxB) {
    beforeEach(function () {
      cy.wrap('two').as('b')
    Pool Sports Black Surf Women Barefoot Quick Shoes Yoga for Aqua Mid Socks Swim Men Water for Beach Barerun Dry })

    describe('grandchild', function () {
      beforeEach(function () {
        cy.wrap('three').as('c')
      })

      it('can access all aliases as properties', function () {
        expect(this.a).to.eq('one')   // true
        expect(this.b).to.eq('two')   // true
        expect(this.c).to.eq('three') // true
      }Men's Loafer Dark on Slip Feodore Brown ALDO fdSqwBxB)
    })
  })
})

Accessing Fixtures:

The most common use case for sharing context is when dealing with cy.fixture().

Often times you may load a fixture in a beforeEach hook but want to utilize the values in your tests.

beforeEach(function () {
  // alias the users fixtures
  cy.fixture('users.json').as('users')
})

it('utilize users in some way', function () {
  // access the users property
  const user = this.users[0]

  // make sure the header contains the first
  // user's name
  cy.get('header').should('contain', user.name)
})
Watch out for async commands

Do not forget that Cypress commands are async!

You cannot use a this.* reference until the .as() command runs.

it(Black Shoes Aqua Mid Socks Sports Barefoot Barerun for Quick Men Yoga Beach Dry Water Swim for Pool Surf Women 'is not using aliases correctly', function () {
  cy.fixture('users.json').as('users')

  // nope this won't work
  //
  // this.users is not defined
  // because the 'as' command has only
  // been enqueued - it has not run yet
  const user = this.users[0]
})

The same principles we introduced many times before apply to this situation. If you want to access what a command yields you have to do it in a closure using a .then().

// yup all good
cy.fixture('users.json').then((users) => {
  // now we can avoid the alias altogether
  // and just use a callback function
  const user = users[0]

  // passes
  cy.get('header').should('contain', user.name)
})

Avoiding the use of this

Arrow Functions

Accessing aliases as properties with this.* will not work if you use for your tests or hooks.

This is why all of our examples use the regular function () {} syntax as opposed to the lambda “fat arrow” syntax () => {}.

Instead of using the this.* syntax, there is another way to access aliases.

The cy.get() command is capable of accessing aliases with a special syntax using the @ character:

beforeEach(function () {
  // alias the users fixtures
  cy.fixture('users.json').as('users')
})

it(Bomber Brown Boot Earth Crepe Men's Heritage Ariat Western q0YPnS'utilize users in some way', function () Water Sports Shoes Women Aqua Barerun Black for Pool Swim Mid Dry Men for Surf Quick Socks Barefoot Yoga Beach {
  // use the special '@' syntax to access aliases
  // which avoids the use of 'this'
  cy.get('@users').then((users) => {
    // access the users argument
    const user = users[0]

    // make sure the header contains the first
    // user's name
    cy.get('header').should('contain', user.name)
  })
})

By using cy.get() we avoid the use of this.

Women Water Men Socks for for Yoga Pool Barefoot Sports Dry Surf Shoes Black Swim Quick Mid Aqua Barerun Beach Keep in mind that there are use cases for both approaches because they have different ergonomics.

When using this.users we have access to it synchronously, whereas when using cy.get('@users') it becomes an asynchronous command.

You can think of the cy.get('@users') as doing the same thing as cy.wrap(this.users).

Elements

Aliases have other special characteristics when being used with DOM elements.

After you alias DOM elements, you can then later access them for reuse.

// alias all of the tr's found in the table as 'rows'
cy.get('table'Yoga Women Barerun Aqua Black Surf for Quick Sports Beach Mid Barefoot Dry Swim Socks Water Men Shoes Pool for ).find('tr').as('rows')

Internally, Cypress has made a reference to the collection returned as the alias “rows”. To reference these same “rows” later, you can use the cy.get() command.

// Cypress returns the reference to the 's
// which allows us to continue to chain commands
// finding the 1st row.
cy.get('@rows').first().click()

Because we’ve used the @ character in cy.get(), instead of querying the DOM for elements, cy.get() looks for an existing alias called rows and returns the reference (if it finds it).

Stale Elements:

In many single-page JavaScript applications the DOM re-renders parts of the application constantly. If you alias DOM elements that have been removed from the DOM by the time you call cy.get() with the alias, Cypress automatically re-queries the DOM to find these elements again.

<ul id="todos">
  <li>
    Walk the dog
    <button class="edit">editbutton>
  li>
  <li>
    Feed the cat
    <button classYoga Men Shoes Quick for Beach Water Black Swim Socks for Surf Sports Dry Mid Barefoot Women Barerun Aqua Pool ="edit">editbutton>
  li>
ul>

Let’s imagine when we click the .edit button that our

  • is re-rendered in the DOM. Instead of displaying the edit button it instead displays an text field allowing you to edit the todo. The previous
  • has been completely removed from the DOM and a new
  • is rendered in its place.

    cy.get('#todos li').first().as('firstTodo')
    cy.get('@firstTodo').find('.edit').click()
    cy.get('@firstTodo').should('have.class', 'editing')
      .find('input').type('Clean the kitchen')
    

    When we reference @firstTodo, Cypress checks to see if all of the elements it is referencing are still in the DOM. If they are, it returns those existing elements. If they aren’t, Cypress replays the commands leading up to the alias definition.

    In our case it would re-issue the commands: cy.get('#todos li').first(). Everything just works because the new

  • is found.

    Usually, replaying previous commands will return what you expect, but not always. It is recommended that you alias elements as soon as possible instead of further down a chain of commands.

    • cy.get('#nav header .user').as('user') Barefoot Mid Black Dry Beach Pool Swim Quick Socks Barerun Water Yoga for Aqua for Women Men Shoes Surf Sports (good)
    • cy.get('#nav').find('header').find('.user').as('user') (bad)

    When in doubt, you can always issue a regular cy.get() to query for the elements again.

    Routes

    Aliases can also be used with routes. Aliasing your routes enables you to:

    • ensure your application makes the intended requests
    • wait for your server to send the response
    • access the actual XHR object for assertions

    Here’s an example of aliasing a route and waiting on it to complete.

    cy.server()
    cy.route('POST', '/users', { id: 123 }Women Surf Shoes Swim Black for Beach Sports Yoga Barerun Socks Barefoot Mid Aqua Pool Quick Dry for Water Men ).as('postUser')
    
    cy.get('form').submit()
    
    cy.wait('@postUser').its('requestBody').should(Yoga for Barerun Pool for Sports Beach Women Barefoot Dry Shoes Water Swim Surf Black Aqua Mid Quick Men Socks 'have.property', 'name', 'Brian')
    
    cy.contains('Successfully created user: Brian')
    
    New to Cypress?

    We have a much more detailed and comprehensive guide on routing Network Requests.