should

Improve this doc

Create an assertion. Assertions are automatically retried until they pass or time out.

An alias of .and()

Note: .should() assumes you are already familiar with core concepts such as assertions

Syntax

.should(chainers)
.should(chainers, value)
.should(chainers, method, value)
.should(callbackFn)

Usage

Correct Usage

cy.get('.error').should('be.empty')                    // Assert that '.error' is empty
cy.contains('Login').should('be.visible')              // Assert that el is visible
cy.wrap({ foo: 'bar' }).its('foo').should('eq', 'bar') // Assert the 'foo' property equals 'bar'

Incorrect Usage

cy.should('eq', '42')   // Errors, cannot be chained off 'cy'

Arguments

chainers (String)

Any valid chainer that comes from Chai or Chai-jQuery or Sinon-Chai.

value (String)

Value to assert against chainer.

method (String)

A method to be called on the chainer.

callbackFn (Function)

Pass a function that can have any number of explicit assertions within it. Whatever was passed to the function is what is yielded.

Yields

In most cases, .should() yields the same subject it was given from the previous command.
cy
  .get('nav')                       // yields <nav>
  .should('be.visible')             // yields <nav>

However, some chainers change the subject. In the example below, the second .should() yields the string sans-serif because the chainer have.css, 'font-family' changes the subject.

cy
  .get('nav')                       // yields <nav>
  .should('be.visible')             // yields <nav>
  .and('have.css', 'font-family')   // yields 'sans-serif'
  .and('match', /serif/)            // yields 'sans-serif'

Examples

Chainers

Assert the checkbox is disabled

cy.get(':checkbox').should('be.disabled')

The current DOM element is yielded

cy.get('option:first').should('be.selected').then(($option) => {
  // $option is yielded
})

Value

Assert the class is ‘form-horizontal’

cy.get('form').should('have.class', 'form-horizontal')

Assert the value is not ‘Jane’

cy.get('input').should('not.have.value', 'Jane')

The current subject is yielded

cy.get('button').should('have.id', 'new-user').then(($button) =>{
  // $button is yielded
})

Method and Value

Assert the href is equal to ‘/users’

// have.attr comes from chai-jquery
cy.get('#header a').should('have.attr', 'href', '/users')

Function

Verify length, content, and classes from multiple <p>

Passing a function to .should() enables you to make multiple assertions on the yielded subject. This also gives you the opportunity to massage what you’d like to assert on.

Just be sure not to include any code that has side effects in your callback function. The callback function will be retried over and over again until no assertions within it throw.

<div>
  <p class="text-primary">Hello World</p>
  <p class="text-danger">You have an error</p>
  <p class="text-default">Try again later</p>
</div>
cy
  .get('p')
  .should(($p) =>{
    // should have found 3 elements
    expect($p).to.have.length(3)

    // make sure the first contains some text content
    expect($p.first()).to.contain('Hello World')

    // use jquery's map to grab all of their classes
    // jquery's map returns a new jquery object
    const classes = $p.map((i, el) => {
      return Cypress.$(el).attr('class')
    })

    // call classes.get() to make this a plain array
    expect(classes.get()).to.deep.eq([
      'text-primary',
      'text-danger',
      'text-default'
    ])
  })

Assert explicitly within .should()

Any errors raised by failed assertions will immediately bubble up and cause the test to fail.

<div id="todos">
  <li>Walk the dog</li>
  <li>Feed the cat</li>
  <li>Write JavaScript</li>
</div>
cy.get('#todos li').should(($lis) => {
  expect($lis).to.have.length(3)
  expect($lis.eq(0)).to.contain('Walk the dog')
  expect($lis.eq(1)).to.contain('Feed the cat')
  expect($lis.eq(2)).to.contain('Write JavaScript')
})

Multiple Assertions

Chaining multiple assertions

Cypress makes it easy to chain assertions together.

In this example we use .and() which is identical to .should().

// our subject is not changed by our first assertion,
// so we can continue to use DOM based assertions
cy.get('option:first').should('be.selected').and('have.value', 'Metallica')

Wait until the assertions pass

Cypress won’t resolve your commands until all of its assertions pass.

// Application Code
$('button').click(() => {
  $button = $(this)

  setTimeout(() => {
    $button.removeClass('inactive').addClass('active')
  }, 1000)
})
cy.get('button').click()
  .should('have.class', 'active')
  .and('not.have.class', 'inactive')

Notes

Subjects

How do I know which assertions change the subject and which keep it the same?

The chainers that come from Chai or Chai-jQuery will always document what they return.

Using a callback function will not change what is yielded

Whatever is returned in the function is ignored. Cypress always forces the command to yield the value from the previous cy command’s yield (which in the example below is <button>)

cy
  .get('button').should(($button) =>{
    expect({foo: 'bar'}).to.deep.eq({foo: 'bar'})
    return {foo: 'bar'} // return is ignored, .should() yields <button>
  })
  .then(($button) => {
    // do anything we want with <button>
  })

Differences

What’s the difference between .then() and .should()/.and()?

Using .then() simply allows you to use the yielded subject in a callback function and should be used when you need to manipulate some values or do some actions.

When using a callback function with .should() or .and(), on the other hand, there is special logic to rerun the callback function until no assertions throw within it. You should be careful of side affects in a .should() or .and() callback function that you would not want performed multiple times.

Rules

Requirements

  • .should() requires being chained off a previous command.

Timeouts

  • .should() will continue to retry its specified assertions until it times out.

cy.get('input', {timeout: 10000}).should('have.value', '10')
  //                    ↲
  // timeout here will be passed down to the '.should()'
  // and it will retry for up to 10 secs
cy.get('input', {timeout: 10000}).should(($input) => {
  //                    ↲
  // timeout here will be passed down to the '.should()'
  // unless an assertion throws earlier,
  // ALL of the assertions will retry for up to 10 secs
  expect($input).to.not.be('disabled')
  expect($input).to.not.have.class('error')
  expect($input).to.have.value('US')
})

Command Log

Assert that there should be 8 children in a nav

cy.get('.left-nav>.nav').children().should('have.length', 8)

The commands above will display in the command log as:

Command Log should

When clicking on assert within the command log, the console outputs the following:

Console Log should

See also