UI / E2E · Junior & Senior

Cypress

A JavaScript-first E2E framework that runs inside the browser — giving you real-time reloading and time-travel debugging that makes frontend testing genuinely enjoyable.

Junior Senior ISTQB CTAL-TAE ~10 min read

1 The Hook — The Wellington Startup's "Heisenbug"

A Wellington-based SaaS startup had a bug that only appeared on the third step of a complex multi-page onboarding form. Developers couldn't reproduce it, and Selenium logs just showed "Timeout waiting for element."

They switched to Cypress and ran the test in the interactive runner. Using Time Travel, they clicked through the command log and saw exactly what happened: at step 3, a specific network request was failing with a 422 error, causing the UI to lock up. Because Cypress runs inside the browser, it caught the network error that the external driver had missed. They fixed the bug in 20 minutes.

2 The Rule — Don't Just Assert; Observe

Use the Cypress runner to watch your tests live. If a test fails, use the Command Log to go back in time and inspect the state of the DOM and Network.

Cypress isn't just a test runner; it's a development environment. Use it to build your features while writing your tests simultaneously.

3 The Analogy — The Flight Recorder

Analogy

The Black Box.

Selenium is like an air traffic controller watching a radar: they see where the plane is, but not what the pilot sees. Cypress is like the Flight Data Recorder inside the cockpit: it records every button press, every gauge reading, and every radio call. When things go wrong, you don't guess — you just play back the tape.

4 Watch Me Do It — NZ SaaS Payment Stubbing

Scenario: Testing a "Successful Payment" screen without actually hitting a live Payment Gateway.

describe('Checkout Flow', () => {
  it('shows success message on successful payment', () => {
    // 1. Intercept the payment API call
    cy.intercept('POST', '/api/v1/nz-payment', {
      statusCode: 200,
      body: { status: 'success', txnId: 'NZ-12345' }
    }).as('paymentRequest');

    // 2. Visit the checkout page
    cy.visit('/checkout');

    // 3. Fill details and submit
    cy.get('[data-testid="pay-button"]').click();

    // 4. Wait for the mocked request
    cy.wait('@paymentRequest');

    // 5. Assert the UI response
    cy.contains('Thank you for your order!').should('be.visible');
  });
});

5 Decision Tool — Why Cypress?

✅ Choose Cypress for...

  • Modern React/Vue/Angular frontends
  • Fast local development cycles
  • Teams that want to mock/stub APIs easily
  • Component-level UI testing

❌ Choose Playwright for...

  • Testing across multiple tabs/windows
  • High-fidelity Safari (WebKit) testing
  • Complex iFrame scenarios
  • Massive parallel execution on cheap CI

6 Common Mistakes

🚫 Using async/await

Don't: const val = await cy.get('...').text();
Actually: Cypress commands are a queue, not Promises. Use .then(($el) => { ... }) or aliases if you need to access values.

🚫 Storing Elements in Variables

Don't: const $btn = cy.get('button'); $btn.click();
Do: cy.get('button').click();
The DOM changes constantly. Chaining ensures Cypress re-queries the element if it goes stale.

7 Now You Try — Setup

📦 Getting Started

Install Cypress in your project:

npm install cypress --save-dev

Open the interactive runner to create your config and example tests:

npx cypress open

8 Self-Check

Q1. Can Cypress test a flow that involves opening a new browser tab?

No. Cypress runs inside a single tab. To test multi-tab flows, you usually have to use a "workaround" (like removing target="_blank") or use Playwright instead.

Q2. What is cy.intercept() used for?

Network Stubbing and Mocking. It allows you to "catch" network requests from your app and return fake data, making it easy to test how your UI handles different server responses without needing a live backend.

9 Interview Prep

"What makes Cypress different from Selenium?"

Answer: "The main difference is architecture. Selenium runs outside the browser and communicates over a network (WebDriver protocol). Cypress runs inside the browser, sharing the same execution loop as the application. This allows for native access to the DOM, zero communication lag, and features like automatic waiting and time-travel debugging."