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.

Senior engineer insight

The moment Cypress clicked for me was when I stopped thinking of it as a test runner and started using it as a development tool. I'd open cypress open alongside my editor and write the feature and the test at the same time — the feedback loop was so tight I could see exactly where my React state management was wrong before I'd even written an assertion. That tight coupling to the browser's execution context is what separates it from every external driver I'd used before.

The most common mistake teams make: they treat Cypress like Selenium with nicer syntax, run it only in CI in headless mode, and miss the entire point of the time-travel debugger.

From the field

A team at a Wellington fintech building Revenue NZ-integrated tax software assumed their Cypress suite was comprehensive because it covered 90% of user journeys. What they hadn't accounted for was the Revenue NZ gateway returning subtly different payload shapes across staging and production environments. Their stubs were too clean — perfectly shaped JSON that never reflected real Revenue NZ response quirks. When they finally wired up cy.intercept() to replay captured production traffic (anonymised), they found three edge cases that had been silently corrupting tax calculations for seven months. The lesson: stub the unhappy path as hard as you stub the happy path, and seed your stubs from real traffic whenever compliance is involved.

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

Why teams fail here

  • Over-relying on UI selectors that devs never agreed to maintain — tests break on every redesign because nobody owns data-testid attributes as a first-class contract.
  • Stubbing everything so aggressively the tests stop testing reality — 100% mocked network means your suite can pass while your real API returns 500s in production.
  • Ignoring Cypress's single-origin constraint until it's too late — NZ SaaS products that authenticate through a third-party IdP (like OneLogin or Azure AD) hit the cross-origin limit and have to retrofit workarounds mid-project.
  • Treating flaky tests as acceptable background noise — one unstable test seeds distrust in the whole suite; teams start skipping failures and the automation becomes ceremonial rather than protective.

Key takeaway

Cypress earns its place when your team treats it as a development accelerator, not a post-coding checkbox — the time-travel debugger only pays off if someone actually opens the runner.

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."