and
Create an assertion. Assertions are automatically retried as part of the previous query until they pass or time out.
An alias of .should()
Note: .and()
assumes you are already familiar with core concepts such as
assertions
Syntax
.and(chainers)
.and(chainers, value)
.and(chainers, method, value)
.and(callbackFn)
Usage
Correct Usage
cy.get('.err').should('be.empty').and('be.hidden') // Assert '.err' is empty & hidden
cy.contains('Login').and('be.visible') // Assert el is visible
cy.wrap({ foo: 'bar' })
.should('have.property', 'foo') // Assert 'foo' property exists
.and('eq', 'bar') // Assert 'foo' property is 'bar'
Incorrect Usage
cy.and('eq', '42') // Can not be chained off 'cy'
cy.get('button').click().and('be.focused') // Should not be chained off
// action commands that may update the DOM
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,
.and()
yields the same subject it was given. .and()
is an assertion, and it is safe to chain further methods.
cy.get('nav') // yields <nav>
.should('be.visible') // yields <nav>
.and('have.class', 'open') // yields <nav>
However, some chainers change the subject. In the example below, .and()
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
Chain assertions on the same subject
cy.get('button').should('have.class', 'active').and('not.be.disabled')
Value
Chain assertions when yield changes
<!-- App Code -->
<ul>
<li>
<a href="users/123/edit">Edit User</a>
</li>
</ul>
cy.get('a')
.should('contain', 'Edit User') // yields <a>
.and('have.attr', 'href') // yields string value of href
.and('match', /users/) // yields string value of href
.and('not.include', '#') // yields string value of href
Method and Value
Assert the href is equal to '/users'
cy.get('#header a')
.should('have.class', 'active')
.and('have.attr', 'href', '/users')
Function
<p>
Verify length, content, and classes from multiple Passing a function to .and()
enables you to assert on the yielded subject.
This gives you the opportunity to massage what you'd like to assert.
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('not.be.empty')
.and(($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',
])
})
Using a callback function will not change the subject
Notes
Chai
Similarities to Chai
If you've worked in Chai before, you will recognize that
.and()
matches the same fluent assertion syntax.
Take this explicit assertion for example:
expect({ foo: 'bar' }).to.have.property('foo').and.eq('bar')
.and()
reproduces this same assertion behavior.
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
Whenever you use a callback function, its return value is always 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('be.active')
.and(($button) => {
expect({ foo: 'bar' }).to.deep.eq({ foo: 'bar' })
return { foo: 'bar' } // return is ignored, .and() yields <button>
})
.then(($button) => {
// do anything we want with <button>
})
Differences
What's the difference between .then()
and .should()
/.and()
?
Using .then()
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
-
.and()
requires being chained off a previous command.
Timeouts
-
.and()
will continue to retry its specified assertions until it times out.
cy.get('input', {timeout: 10000}).should('have.value', '10').and('have.class', 'error')
↲
// timeout here will be passed down to the '.and()'
// and it will retry for up to 10 secs
cy.get('input', {timeout: 10000}).should('have.value', 'US').and(($input) => {
↲
// timeout here will be passed down to the '.and()'
// 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')
})
Command Log
Chain assertions on the same subject
cy.get('.list')
.find('input[type="checkbox"]')
.should('be.checked')
.and('not.be.disabled')
The commands above will display in the Command Log as:
When clicking on assert
within the command log, the console outputs the
following: