What Is Cypress and How It Works

7 min read

Cypress is an open-source, JavaScript- and TypeScript-first end-to-end testing framework built for the modern web. It was designed by people who had spent years debugging Selenium suites and decided the architecture itself was the problem. The result is a tool that runs inside your browser alongside your application, gives you time-travel debugging, and waits for the DOM automatically — no sleep(2000) calls, no driver process, no flaky timing.

This first lesson is the only one in the course without runnable test code. The rest of chapter 1 gets you installed and writing your first real spec — but understanding why Cypress works the way it does is what stops you fighting the framework later.

How Cypress is different from Selenium

Selenium has been the industry standard for fifteen years. It works like this: your test process runs in one operating-system process, the browser runs in another, and the WebDriver protocol sits between them, sending each command over a local HTTP connection. Click a button → encode the command → send it over HTTP → browser receives it → executes → encodes the result → sends it back. Every action pays that round-trip cost.

Cypress made a different bet. The Cypress test runner injects your test code straight into the browser as a frame next to your app. Your tests and your application run in the same JavaScript event loop. Calling cy.get() doesn't cross any process boundary — it's a function call in the same V8 instance that's running your React or Vue or Svelte app. There is no driver, no protocol, no marshalling.

This single architectural choice cascades into everything you'll like about Cypress: speed, reliability, debuggability, network control, and the Time Travel feature you'll meet in lesson 4.

Selenium vs Cypress, side by side

Where the test code actually runs

Selenium / WebDriver

  • Test process runs in Node / Java / Python — outside the browser

  • Each command travels over HTTP via the WebDriver protocol

  • Network round-trip on every click, type, and assertion

  • Built-in waiting is limited; teams reach for sleep() and explicit waits

Cypress

  • Test code is injected into the browser as a sibling frame to the app

  • Tests and app share one JavaScript event loop

  • No protocol overhead — commands are direct DOM/network calls

  • Auto-retry built into every command — no manual sleeps

What Cypress can — and can't — test

Because Cypress lives in the browser, it can drive anything the browser can render. That means:

  • Single-page apps built with React, Vue, Angular, Svelte, Solid, anything.
  • Server-rendered pages — Next.js, Rails, Django, Laravel, plain HTML.
  • Web components and shadow DOM (with the includeShadowDom config flag).
  • REST and GraphQL APIs directly via cy.request, separate from any UI.
  • Network-level mocking via cy.intercept — you can stub a 500 error from /api/checkout without touching backend code.

It also has real limitations you need to know up front:

  • Multiple browser tabs at the same time. Cypress runs one tab. If your test opens a second tab, Cypress can't drive it directly. The workaround is usually to assert on the URL the new tab would have opened, or rewrite the link as same-tab.
  • Cross-origin navigation used to be a hard wall; Cypress 12+ supports it via cy.origin('other.com', () => { ... }), but it's a niche tool reserved for SSO flows.
  • Native mobile apps and desktop apps. Cypress is browser-only. Use Appium, Playwright, or a native testing framework for those.
  • Multiple browsers in parallel within one test. A single it block runs in one browser session.

For 95% of QA engineering work on web products, none of these are blockers.

The two ways to run Cypress

Cypress has two surfaces and you'll use both:

The Test Runner (npx cypress open) is a desktop application. It opens a real browser, shows your application on the right, and a live command log on the left. You write a test, save the file, and the runner re-executes it within milliseconds. This is your interactive development environment — you'll spend most of your authoring time here. Lesson 4 dives deep into it.

The CLI (npx cypress run) runs your tests headlessly from the terminal. No UI, no live reload, just a serial run with a final report. This is the mode CI pipelines use. By default it captures screenshots on failure and a video of every spec, both invaluable for debugging a CI-only failure.

The same test files run in both modes. You author against the runner, you ship through the CLI.

Why teams pick Cypress for QA work

Once Cypress is wired up, the day-to-day developer experience pulls ahead:

  • Time travel. Hover over any command in the log and Cypress shows the DOM as it was at that moment. Failed assertions become a five-second diagnosis instead of a fifteen-minute one.
  • Automatic waiting and retries. cy.get('[data-testid="checkout-total"]').should('contain', '$129.99') will keep re-querying for up to four seconds until both the element exists and the assertion passes. You almost never write an explicit wait.
  • Network stubbing built in. cy.intercept('GET', '/api/orders', { fixture: 'empty-orders.json' }) and your test runs against a deterministic fake response. No mock server to maintain.
  • Real-time reloading. Save the spec; the runner re-runs it. The feedback loop is closer to a hot-reloaded React app than a traditional test framework.
  • Screenshots and videos by default. The CLI captures evidence of every failure with no configuration on your side.
  • TypeScript out of the box. No plugin, no transpiler dance. Cypress ships its own type declarations and can execute .ts spec files directly. Custom commands type-merge into the global cy.* namespace via interface declaration merging.

Browser support and licensing

Cypress runs Chrome, Edge, Firefox, and its own bundled Electron build. WebKit / Safari support is experimental at the time of writing — fine for spot-checks, not yet for production CI. If iOS-Safari coverage is a hard requirement, pair Cypress with a separate Playwright suite for that browser.

The framework itself is free and open-source under the MIT licence. Cypress Cloud (the analytics dashboard, parallelisation coordinator, and flake detector you'll meet in chapter 8) is a paid SaaS add-on. You can run Cypress in CI without it; the Cloud only kicks in when you pass --record --parallel.

Where Cypress sits in the QA toolkit

If you spend any of your time writing JavaScript-ecosystem automation, Cypress is the most popular choice in that space — by GitHub stars, npm downloads, and job-posting frequency. The patterns transfer to Playwright and WebdriverIO if you switch later, so this isn't a dead-end skill. The Cypress commands cheat sheet on qa.codes is a useful one-page reference for everything in the API; we'll work through every section of it across the next nine chapters.

⚠️ Common mistakes

  • Treating Cypress as a drop-in replacement for Selenium. The architecture is different on purpose. Patterns that worked in Selenium — explicit waits, Thread.sleep, manual driver-management — are anti-patterns in Cypress. Lean on auto-retry and should assertions instead. Trying to force Selenium habits onto Cypress produces slow, flaky tests that miss the framework's biggest wins.
  • Reaching for Cypress when you need cross-browser parity on Safari/iOS. Experimental WebKit support is not the same as production support. If your audience is heavy on iOS users, do not let Cypress be your only browser-coverage signal. Pair it with Playwright or a real device cloud.
  • Thinking "in-browser test runner" means "no CI." The cypress run CLI exists for exactly this reason. Author in the Test Runner; run in CI via the CLI. Skipping CI because the desktop app is so pleasant is one of the most expensive mistakes a new Cypress team makes.

🎯 Practice task

Get oriented before installing anything. 15-20 minutes.

  1. Open the Cypress homepage and the Cypress GitHub repository in two browser tabs. Spend five minutes scanning each — note the version number, the licence, and the issue count. You're calibrating which framework you're about to commit to.
  2. Open a real-world public Cypress test suite (the Cypress Real World App is the canonical reference). Read one spec file end to end without running it. Don't try to understand every command — just notice the shape: describe, it, beforeEach, cy.visit, cy.get, should. You're learning to recognise the rhythm of a Cypress test before you write one.
  3. Make a one-page note answering these in your own words:
    • Why does Cypress not need WebDriver?
    • What can Cypress test that Selenium can — and what can't it?
    • When would your team still pick Selenium or Playwright?
  4. Stretch: find a Cypress test that uses cy.intercept in the Real World App. Read the lines around it and write a one-sentence guess at what it's stubbing. You'll learn the actual API in chapter 4 — for now, just notice that network mocking lives next to UI code in the same test file.

You now have a clear picture of what Cypress is and why teams adopt it. The next lesson installs Cypress with TypeScript and walks you through every file the scaffold creates.

// tip to track lessons you complete and pick up where you left off across devices.