Assertions with should() and expect()
Assertions are how a Cypress test declares what it expects to be true about the application, and Cypress bundles Chai, Chai-jQuery, and Sinon-Chai so you get a rich vocabulary of assertion chainers out of the box — things like 'be.visible', 'have.text', 'have.length', and 'have.been.calledOnce' for spies and stubs. Every assertion compares actual application state to an explicit expected value rather than merely observing that a command ran.
Cricket analogy: A third umpire doesn't just watch the replay; he checks it against a specific rule, like whether the bail was dislodged before the stumping was completed, similar to how a Cypress assertion checks the DOM against a specific expected condition rather than just observing it.
should() — Retrying, Subject-Chained Assertions
should() is chained directly onto a command like cy.get() and takes one or more chainer strings describing the expected condition, such as cy.get('.alert').should('be.visible'). Crucially, should() doesn't just check once: it re-runs the preceding cy.get() query and re-evaluates the condition repeatedly, which is what allows a test to wait naturally for an element that appears only after an animation or network response completes.
Cricket analogy: Hawk-Eye keeps re-tracking the ball's trajectory until it's confident the prediction is stable before showing the final verdict, similar to how cy.get('.alert').should('be.visible') keeps re-querying the alert element and re-checking visibility until the assertion passes or times out.
cy.get('.alert')
.should('be.visible')
.and('contain', 'Success');
cy.get('.cart-count').should('have.text', '3');expect() — One-Time, Explicit Assertions
expect() is Chai's standalone assertion function, typically used inside a cy.then() callback to check a value you've already captured, for example expect(price).to.be.greaterThan(0). Unlike should(), expect() performs its check exactly once against the value passed in — it has no awareness of the DOM and doesn't retry, so it's best suited for verifying computed or derived JavaScript values rather than waiting on asynchronous UI state.
Cricket analogy: Once the ball is dead and the over is complete, the scorer records that ball's outcome permanently in the book without re-checking it later, similar to how expect(text).to.equal('Sold Out') inside a cy.then() callback checks a captured value once, without Cypress retrying it.
Chai also offers a BDD-style assert API (assert.equal(a, b)) as an alternative to expect(). Both work identically inside cy.then(); expect() is more common because its fluent, readable syntax (expect(x).to.equal(y)) matches the chainer style used elsewhere in Cypress tests.
Choosing the Right Assertion Style
As a rule of thumb, use should() (or and()) for anything checking live DOM state, since retry-ability is exactly what makes UI assertions reliable against asynchronous rendering. Reach for expect() inside cy.then() when you need to run custom JavaScript logic on a captured value — like summing an array of prices pulled from the DOM — where Cypress's built-in chainers alone can't express the check.
Cricket analogy: A team analyst uses live ball-by-ball tracking to judge current match momentum but a separate post-match report to calculate season averages, similar to using should() for live, retrying DOM checks and expect() inside cy.then() for one-off computed value checks.
Chaining multiple, loosely related conditions onto a single should() (or worse, burying several expect() calls inside one cy.then()) can make a failing test hard to diagnose, since you only see that 'the assertion' failed. Prefer separate should()/and() calls, or clearly named expect() checks, so a failure points precisely at which condition broke.
- Cypress bundles Chai, Chai-jQuery, and Sinon-Chai, giving access to chainers like be.visible, have.text, and have.been.calledOnce.
- should()/and() chain onto a command and re-run both the query and the assertion until it passes or times out.
- expect() is Chai's standalone assertion, typically used inside cy.then() to check an already-captured value once.
- expect() does not retry — it's best for verifying computed or derived JavaScript values, not live DOM state.
- Prefer should() for anything checking live, asynchronous UI state.
- Avoid overloading a single should() chain or cy.then() callback with unrelated checks, since it obscures which condition actually failed.
Practice what you learned
1. What assertion libraries does Cypress bundle by default?
2. What makes should() different from a single expect() call?
3. Where is expect() typically used in a Cypress test?
4. Which is best suited for verifying that a UI element eventually becomes visible after an API call?
5. What's a risk of bundling several unrelated checks into one should() chain?
Was this page helpful?
You May Also Like
Selecting Elements with cy.get()
Learn how Cypress's cy.get() command queries the DOM using CSS selectors, and how to choose selectors that are stable, readable, and resistant to markup changes.
Chaining and Retry-ability
Understand how Cypress commands chain together via the command queue and how built-in retry-ability makes assertions resilient to asynchronous UI changes.
Interacting with Elements (type, click, check)
Cover Cypress's core interaction commands — type(), click(), check(), select() — and the actionability checks Cypress performs before firing each one.