0
0
Cypresstesting~15 mins

expect() for BDD assertions in Cypress - Deep Dive

Choose your learning style9 modes available
Overview - expect() for BDD assertions
What is it?
The expect() function is used in Cypress to write BDD-style assertions. It checks if a value meets certain conditions, like equality or existence, and helps confirm that your app works as expected. These assertions are written in a readable way, making tests easier to understand. They form the backbone of verifying behavior in automated tests.
Why it matters
Without expect(), tests would be hard to read and understand, making it difficult to know what is being checked. It solves the problem of clearly stating what the expected outcome of a test is. Without it, bugs could slip through unnoticed, causing broken features and unhappy users. Expect() helps catch errors early by making test intentions clear and precise.
Where it fits
Before learning expect(), you should know basic JavaScript and how Cypress runs tests. After mastering expect(), you can learn advanced assertions, custom commands, and how to combine expect() with Cypress commands for full end-to-end testing.
Mental Model
Core Idea
expect() is a clear question you ask about your app’s state, and it tells you if the answer matches what you expect.
Think of it like...
Using expect() is like checking a recipe while cooking: you look at the dish and ask, 'Is this salty enough?' If yes, you continue; if no, you fix it. Similarly, expect() checks if the app’s output matches the recipe (test).
┌─────────────┐
│  Actual     │
│  Value      │
└─────┬───────┘
      │
      ▼
┌─────────────┐      ┌─────────────┐
│  expect()   │─────▶│  Assertion  │
│  function   │      │  (matcher)  │
└─────────────┘      └─────────────┘
      │                    │
      ▼                    ▼
┌─────────────┐      ┌─────────────┐
│ Pass/Fail   │◀────│  Test Runner │
│ Result      │      │  Reports    │
└─────────────┘      └─────────────┘
Build-Up - 6 Steps
1
FoundationBasic expect() usage in Cypress
🤔
Concept: Learn how to write a simple expect() assertion to check if a value equals another.
In Cypress, you use expect() to check values. For example, expect(5).to.equal(5) checks if 5 equals 5. If true, the test passes; if false, it fails. This is the simplest way to confirm something in your app.
Result
The test passes because 5 equals 5.
Understanding the simplest form of expect() builds the foundation for all other assertions.
2
FoundationCommon matchers with expect()
🤔
Concept: Introduce common matchers like .to.equal(), .to.be.true, and .to.include() used with expect().
Matchers are words that describe what you want to check. Examples: - expect(true).to.be.true checks if value is true - expect('hello').to.include('ell') checks if string contains 'ell' - expect([1,2,3]).to.have.length(3) checks array length These let you test many conditions easily.
Result
Tests pass when the actual values meet the matcher conditions.
Knowing common matchers lets you write clear and precise tests for many scenarios.
3
IntermediateUsing expect() with Cypress commands
🤔Before reading on: do you think expect() can directly check values returned by Cypress commands like cy.get()? Commit to your answer.
Concept: Learn how to combine expect() with Cypress commands that return elements or values asynchronously.
Cypress commands like cy.get() return elements asynchronously. To check them, you use .then() to get the value, then apply expect(). Example: cy.get('h1').then($el => { expect($el.text()).to.equal('Welcome') }) This waits for the element, then checks its text.
Result
The test passes if the h1 text is 'Welcome'.
Understanding Cypress’s async nature is key to using expect() correctly with commands.
4
IntermediateChaining expect() for multiple assertions
🤔Before reading on: can you chain multiple expect() assertions on the same value, or do you need separate calls? Commit to your answer.
Concept: Learn how to write multiple assertions on one value using separate expect() calls.
You cannot chain multiple expect() calls on the same value directly. Instead, write separate expect() statements: const value = 10 expect(value).to.be.a('number') expect(value).to.be.greaterThan(5) This checks type and value separately.
Result
Both assertions pass if value is a number greater than 5.
Knowing how to organize multiple checks prevents confusion and test errors.
5
AdvancedCustom error messages with expect()
🤔Before reading on: do you think expect() lets you add your own error messages when assertions fail? Commit to your answer.
Concept: Learn how to add custom messages to expect() assertions for clearer test failure reports.
You can add a custom message as the second argument in some matchers: expect(value, 'Check if value is positive').to.be.greaterThan(0) If the test fails, this message appears in the report, helping you understand what went wrong.
Result
If value is not greater than 0, the test fails with the custom message.
Custom messages improve debugging by making failure reasons clearer.
6
ExpertHandling asynchronous values in expect()
🤔Before reading on: do you think expect() can handle promises directly, or do you need special handling? Commit to your answer.
Concept: Understand how to correctly assert values that come from promises or async operations in Cypress tests.
expect() does not wait for promises. You must resolve them first: cy.wrap(Promise.resolve(5)).then(value => { expect(value).to.equal(5) }) Trying expect(Promise.resolve(5)).to.equal(5) fails because expect() sees the promise object, not its result.
Result
The test passes because the promise is resolved before assertion.
Knowing how to handle async values prevents common test failures and flaky tests.
Under the Hood
expect() creates an assertion object wrapping the actual value. It uses matcher functions to compare this value against expected conditions. When a matcher runs, it throws an error if the condition fails, which Cypress catches to mark the test as failed. Cypress integrates expect() with its command queue, handling asynchronous waits and retries before assertions run.
Why designed this way?
expect() follows the Behavior-Driven Development style to make tests readable and expressive. It was designed to separate the checking logic (matcher) from the value, making tests clear. Cypress uses this design to combine synchronous assertions with asynchronous commands, improving test reliability and developer experience.
┌───────────────┐
│ Actual Value  │
└──────┬────────┘
       │
       ▼
┌───────────────┐      ┌───────────────┐
│  expect()     │─────▶│  Matcher      │
│  Wrapper      │      │  Function     │
└──────┬────────┘      └──────┬────────┘
       │                      │
       ▼                      ▼
┌───────────────┐      ┌───────────────┐
│ Assertion     │◀─────│ Pass/Fail     │
│ Result        │      │ Decision      │
└───────────────┘      └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does expect() automatically wait for elements in Cypress? Commit to yes or no.
Common Belief:expect() waits for elements or values to appear before checking.
Tap to reveal reality
Reality:expect() does not wait; Cypress commands like cy.get() handle waiting. You must use .then() or Cypress commands to get values before expect().
Why it matters:Assuming expect() waits causes flaky tests that fail because the value isn't ready yet.
Quick: Can you chain multiple matchers directly on one expect() call? Commit to yes or no.
Common Belief:You can chain many matchers on a single expect() call like expect(value).to.be.a('string').to.include('x').to.have.length(5).
Tap to reveal reality
Reality:Matchers do not chain like that; each expect() call checks one condition. You write multiple expect() calls for multiple checks.
Why it matters:Trying to chain matchers causes syntax errors or unexpected test behavior.
Quick: Does expect() handle promises automatically? Commit to yes or no.
Common Belief:expect() can directly assert on promises without extra handling.
Tap to reveal reality
Reality:expect() sees the promise object, not its resolved value. You must resolve promises before asserting.
Why it matters:Misusing expect() with promises leads to false test failures and confusion.
Quick: Is expect() only useful for checking equality? Commit to yes or no.
Common Belief:expect() is mainly for checking if two values are equal.
Tap to reveal reality
Reality:expect() supports many matchers like type checks, inclusion, length, truthiness, and custom assertions.
Why it matters:Limiting expect() to equality checks wastes its power and leads to less expressive tests.
Expert Zone
1
expect() assertions run synchronously but depend on Cypress commands to handle asynchronous waits, requiring careful chaining.
2
Custom matchers can be added to extend expect() for domain-specific checks, improving test clarity in large projects.
3
Using custom error messages in expect() helps quickly identify which assertion failed in complex test suites.
When NOT to use
expect() is not suitable for waiting on elements or retrying assertions; use Cypress commands like cy.should() for automatic retries and waits. For complex asynchronous flows, prefer Cypress’s built-in assertions over raw expect() calls.
Production Patterns
In real projects, expect() is combined with Cypress commands inside .then() callbacks to assert dynamic content. Teams often create custom commands wrapping expect() for reusable checks. Tests use descriptive custom messages to speed up debugging in CI pipelines.
Connections
Behavior-Driven Development (BDD)
expect() is a core part of BDD-style testing syntax.
Understanding expect() helps grasp how BDD makes tests readable and focused on behavior, not implementation.
Promises and Asynchronous JavaScript
expect() assertions require resolved values, connecting to how promises work in JavaScript.
Knowing how promises resolve clarifies why expect() needs values, not promises, preventing common async test errors.
Quality Control in Manufacturing
expect() acts like a quality inspector checking if products meet standards.
Seeing expect() as a quality check helps understand its role in catching defects early, just like in factories.
Common Pitfalls
#1Trying to assert on a Cypress command directly without resolving it.
Wrong approach:expect(cy.get('button')).to.exist
Correct approach:cy.get('button').then($btn => { expect($btn).to.exist })
Root cause:Misunderstanding that Cypress commands are asynchronous and return chainable objects, not direct values.
#2Chaining multiple matchers on one expect() call incorrectly.
Wrong approach:expect('hello').to.be.a('string').to.include('h')
Correct approach:expect('hello').to.be.a('string'); expect('hello').to.include('h')
Root cause:Confusing matcher chaining with separate assertions; matchers do not chain like methods.
#3Using expect() directly on a promise without resolving it.
Wrong approach:expect(Promise.resolve(10)).to.equal(10)
Correct approach:Promise.resolve(10).then(value => { expect(value).to.equal(10) })
Root cause:Not understanding that expect() compares actual values, not promise objects.
Key Takeaways
expect() is a readable way to check if your app behaves as expected in Cypress tests.
Matchers like .to.equal() and .to.include() let you test many conditions clearly and precisely.
Because Cypress commands are asynchronous, you must resolve values before using expect() to avoid flaky tests.
Multiple assertions require separate expect() calls; matchers do not chain on one expect().
Custom messages and proper async handling with expect() improve test clarity and reliability in real projects.