Skip to content

Cypress Assertions

Assertions are how a Cypress test actually verifies something is true. This lesson introduces implicit and explicit assertions and explains why Cypress assertions retry automatically instead of failing instantly.

What Is an Assertion?

An assertion is a statement about expected state, an element should be visible, a value should equal something, a request should have happened. Cypress assertions are built on top of Chai, Chai-jQuery, and Sinon-Chai, giving you a large, expressive vocabulary of checks.

Assertions come in two flavors: implicit, chained directly with .should() or .and(), and explicit, using expect() or assert() inside a .then() callback for more complex logic.

// Implicit assertion, retried automatically
cy.get('[data-cy="status"]').should('have.text', 'Complete');

// Explicit assertion, runs once, inside .then()
cy.get('[data-cy="total"]').then(($el) => {
  const value = Number($el.text().replace('$', ''));
  expect(value).to.be.greaterThan(0);
});

The implicit version retries until it passes or times out; the explicit version runs exactly once, when the callback executes.

Assertion Syntax Forms

.should('be.visible')
.should('have.text', 'Complete')
.and('have.class', 'active')
expect(value).to.equal(5);
assert.equal(value, 5);
  • .should() is the primary implicit assertion command, retried automatically.
  • .and() is an alias for .should(), purely for chaining readability.
  • expect() (BDD style) and assert() (TDD style) are explicit, one-time checks used inside callbacks.
  • Implicit assertions should be preferred whenever the check can be expressed that way.

Assertion Style Cheat Sheet

When to reach for each assertion style Cypress supports.

Style Example Retried?
Implicit (.should) .should('be.visible') Yes, automatically
Implicit (.and) .should(...).and('have.class', 'x') Yes, automatically
Explicit (expect) expect(value).to.equal(5) No, runs once in .then()
Explicit (assert) assert.isTrue(flag) No, runs once in .then()

Why Implicit Assertions Retry Automatically

Web applications are inherently asynchronous, data loads, animations run, and state updates after a delay. If assertions failed the instant they ran, nearly every test would need manual waits sprinkled everywhere to avoid false failures.

Instead, .should() re-runs its check repeatedly (re-querying the DOM each time) until it passes or the default command timeout elapses, at which point it reports the final observed value in the failure message.

// No manual wait needed: retries until the class appears
cy.get('[data-cy="save-button"]').should('have.class', 'is-saved');

Using .should() with a Callback Function

.should() also accepts a callback function for assertions that don't map cleanly to a built-in Chai chainer. Cypress retries the entire callback until it stops throwing, which preserves retry-ability even for custom logic.

cy.get('[data-cy="price-list"] li').should(($items) => {
  expect($items).to.have.length.greaterThan(0);
  expect($items.first()).to.contain.text('$');
});

Any thrown error inside the callback counts as a failed attempt and triggers a retry, exactly like a built-in assertion.

Common Mistakes

  • Wrapping every assertion in .then() with expect(), losing Cypress's automatic retry-ability for no reason.
  • Assuming an assertion fails instantly, when it may legitimately retry for several seconds before reporting failure.
  • Writing side-effecting code (like clicking) inside a .should(callback), which can run multiple times during retries.
  • Not reading the actual vs. expected values in a failed assertion message before assuming the application is broken.

Key Takeaways

  • Assertions come in implicit (.should()/.and()) and explicit (expect()/assert()) forms.
  • Implicit assertions retry automatically; explicit assertions run exactly once inside .then().
  • .should() also accepts a callback for custom checks while preserving retry behavior.
  • Prefer implicit assertions whenever possible for more resilient, less flaky tests.

Pro Tip

Default to implicit assertions (.should()) and only drop into .then()/expect() when the check genuinely cannot be expressed as a chainable assertion, this single habit eliminates a large share of common Cypress flakiness.