Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Cypress User Guide

Generated June 2026 from cypress-io/cypress at 1f8ff3b

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Cypress is a front-end testing tool for anything that runs in a browser. You write tests in JavaScript or TypeScript, and Cypress runs them inside the same run loop as your application — giving you native access to every object, while it automatically waits, retries, and snapshots the DOM at each step. It covers two testing types from one install:

  • End-to-End (E2E) testing — drive a real, deployed application through a real browser (cy.visit('/login'), type, click, assert).
  • Component testing — mount a single React, Vue, Angular, or Svelte component in isolation and test it like a unit, but in a real browser.

This guide is everything you need to install Cypress, write and run tests, configure projects, stub the network, and ship reliable tests in CI. It is built directly from the Cypress source code at commit 1f8ff3b.

Note

Cypress installs as a single npm package (cypress) that downloads a self-contained binary (the Test Runner, bundled with its own Electron browser). You do not need to install a separate browser driver, Selenium, or WebDriver server.


1. Quick Start

Get a working test in under five minutes.

# 1. Initialize a project (skip if you already have package.json)
npm init -y

# 2. Install Cypress as a dev dependency
npm install --save-dev cypress

# 3. Open the Cypress App (interactive Test Runner)
npx cypress open
It looks like this is your first time using Cypress: 14.x.x

 ✔  Verified Cypress! C:\Users\you\AppData\Local\Cypress\Cache\14.x.x\Cypress

Opening Cypress...

The Cypress App launches. Choose E2E Testing, let Cypress scaffold the config files, pick a browser, and click Create new spec. Cypress writes a starter spec and runs it live in the browser.

A first end-to-end test looks like this:

// cypress/e2e/spec.cy.js
describe('My First Test', () => {
  it('visits the app and checks the title', () => {
    cy.visit('https://example.cypress.io')
    cy.contains('type').click()
    cy.url().should('include', '/commands/actions')
    cy.get('.action-email')
      .type('[email removed]')
      .should('have.value', '[email removed]')
  })
})

Tip

Use cy.visit() to load a page, cy.get() / cy.contains() to query elements, action commands like .click() and .type() to interact, and .should() to assert. Cypress automatically waits for elements to exist and for assertions to pass — you almost never need manual waits or sleeps.


2. Installation

2.1 Requirements

Requirement Detail
Node.js >= 22.19.0 (declared in the package engines field)
Operating systems macOS 11+ (Intel/Apple Silicon), Linux (Debian/Ubuntu, Fedora, etc.), Windows 10/11
Package manager npm, Yarn (Classic or Berry/PnP), or pnpm
Disk ~1 GB free for the downloaded binary and its cache

Important

Cypress ships its own browser (Electron) and bundles the entire Test Runner. The cypress npm package is small; the heavy binary is downloaded on first install and cached globally per version, not per project.

2.2 Install the package

npm

npm install --save-dev cypress

Yarn

yarn add --dev cypress

pnpm

pnpm add --save-dev cypress

Installing the package triggers a postinstall step that downloads and unzips the Cypress binary into the global cache.

Installing Cypress (version: 14.x.x)

 ✔  Downloaded Cypress
 ✔  Unzipped Cypress
 ✔  Finished Installation C:\Users\you\AppData\Local\Cypress\Cache\14.x.x

2.3 Verify the installation

npx cypress verify
✔  Verified Cypress! C:\Users\you\AppData\Local\Cypress\Cache\14.x.x\Cypress

Print full environment information (binary version, cache location, browsers detected):

npx cypress info

2.4 Controlling the binary download

The download is driven by environment variables read at install time:

Variable Effect
CYPRESS_INSTALL_BINARY Set to a version, a URL, a local .zip path, or 0 to skip the download entirely
CYPRESS_DOWNLOAD_MIRROR Point the download at a private mirror
CYPRESS_CACHE_FOLDER Override the global binary cache location
CYPRESS_DOWNLOAD_USE_CA Use the system / npm CA bundle for the download request
HTTP_PROXY / HTTPS_PROXY / NO_PROXY Standard proxy variables — honored for the binary download

Caution

If you install with CYPRESS_INSTALL_BINARY=0 (common in Docker base images), you must provide the binary another way before running tests, or cypress run will fail to verify. Run npx cypress install once the binary is available.

2.5 Managing the binary cache

The cypress cache command manages downloaded binaries:

npx cypress cache path     # print the cache folder
npx cypress cache list     # list cached versions (add --size for disk usage)
npx cypress cache clear    # remove ALL cached binaries
npx cypress cache prune    # remove all cached versions EXCEPT the currently installed one

Tip

Run npx cypress cache prune periodically on CI build agents and developer machines to reclaim disk from old Cypress versions.


3. Setting Up a Project

3.1 Open the Cypress App

npx cypress open

On first launch Cypress walks you through choosing a testing type (E2E or Component) and scaffolds the required files:

  • cypress.config.js (or .ts / .mjs) — your project configuration
  • cypress/support/e2e.js and/or cypress/support/component.js — support files loaded before every spec
  • cypress/fixtures/ — static test data
  • cypress/e2e/ — where your E2E specs live

3.2 The configuration file

Cypress is configured with a cypress.config.js file at your project root using defineConfig:

// cypress.config.js
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
    setupNodeEvents(on, config) {
      // register tasks, plugins, and event listeners here
    },
  },
})
// cypress.config.ts
import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
})

Note

The default config filename is cypress.config.js. You can change it with --config-file on the CLI. TypeScript (cypress.config.ts) and ESM (cypress.config.mjs) config files are supported out of the box.

3.3 Project folder layout

Folder / file Default Purpose
cypress/e2e/ from specPattern E2E spec files (*.cy.js)
cypress/fixtures/ cypress/fixtures (fixturesFolder) Static JSON / data loaded by cy.fixture()
cypress/support/e2e.js cypress/support/e2e.{js,jsx,ts,tsx} (supportFile) Runs before every E2E spec — custom commands, global hooks
cypress/support/component.js cypress/support/component.{js,jsx,ts,tsx} Runs before every component spec
cypress/downloads/ cypress/downloads (downloadsFolder) Files downloaded during tests
cypress/screenshots/ cypress/screenshots (screenshotsFolder) Saved screenshots
cypress/videos/ cypress/videos (videosFolder) Recorded run videos (when video: true)

4. Writing Tests

Cypress uses the Mocha describe/it BDD structure and Chai assertions, with jQuery-style DOM querying. You don't import these — they are globals inside specs.

4.1 Test structure

describe('Login page', () => {
  beforeEach(() => {
    cy.visit('/login')
  })

  it('shows an error for bad credentials', () => {
    cy.get('[data-cy="username"]').type('wrong')
    cy.get('[data-cy="password"]').type('nope')
    cy.get('[data-cy="submit"]').click()
    cy.get('.error').should('contain', 'Invalid credentials')
  })
})
Hook When it runs
before() Once, before all tests in the block
beforeEach() Before every test
afterEach() After every test
after() Once, after all tests in the block

4.2 The command chain and subjects

Cypress commands are asynchronous and chainable. Each command yields a subject to the next:

cy.get('ul.todo-list')   // yields the <ul> element
  .find('li')            // yields the <li> children
  .first()               // yields the first <li>
  .should('contain', 'Buy milk')  // asserts on it

Important

Commands do not run when the line executes — they are enqueued and run in order after the test function returns. This is why you cannot assign a command's return value to a variable. Use .then() to work with yielded values, or aliases (.as()) to reuse them.

// WRONG — value is a Chainable, not the element
const button = cy.get('button')

// RIGHT — work with the subject inside .then()
cy.get('button').then(($button) => {
  // $button is the jQuery-wrapped element
})

4.3 Automatic waiting and retry-ability

Cypress automatically retries queries (like cy.get) and assertions until they pass or a timeout is reached. The default command timeout is 4000 ms (defaultCommandTimeout). This means you rarely need cy.wait(ms):

// Cypress retries cy.get + the assertion until the element appears
// with the right text, or 4s elapses — no manual wait needed
cy.get('.async-result').should('have.text', 'Loaded')

Tip

If you find yourself adding cy.wait(2000), replace it with an assertion on the thing you're actually waiting for, or wait on a network request alias (see §8). Hard-coded waits make tests slow and flaky.


5. Command Reference

Every command below is a method on the cy global (or, for the listed event/utility methods, on Cypress). Commands marked query are automatically retried; action commands interact with the DOM and require a connected, visible, actionable element.

5.1 Querying the DOM (retried automatically)

Command Yields Description
cy.get(selector) element(s) Get DOM elements by CSS selector or alias (@name)
cy.contains(text) element Get the element containing the given text
cy.find(selector) element(s) Find descendants of the current subject
cy.within(fn) — Scope all commands inside fn to the current element
cy.root() element Get the root element (document or within subject)
cy.focused() element Get the element that currently has focus
cy.shadow() element(s) Traverse into the shadow DOM of the subject
cy.get('[data-cy="email"]')
cy.contains('Submit').click()
cy.get('form').within(() => {
  cy.get('input[name="email"]').type('[email removed]')   // scoped to the form
})

Tip

Prefer dedicated data-* test attributes (e.g. [data-cy="submit"]) over CSS classes or text that change with styling and copy. This is the single most effective way to reduce selector flakiness.

5.2 Traversal (retried automatically)

children, closest, eq, filter, first, last, next, nextAll, nextUntil, not, parent, parents, parentsUntil, prev, prevAll, prevUntil, siblings.

cy.get('li').first()                 // first matching element
cy.get('li').eq(2)                   // the third element (0-indexed)
cy.get('.active').parent()           // the parent element
cy.get('tr').filter('.selected')     // narrow the set
cy.get('#start').next().siblings()   // walk the DOM

5.3 Actions (interact with elements)

Command Description
.click() Click an element ({ force: true } to bypass actionability)
.dblclick() Double-click
.rightclick() Right-click (context menu)
.type(text) Type into an input; supports key sequences like {enter}, {backspace}, {selectall}
.clear() Clear an input or textarea
.check() / .uncheck() Check/uncheck checkboxes and radios
.select(value) Select an <option> from a <select>
.selectFile(path) Attach a file to a file input (or drag-drop)
.scrollIntoView() Scroll an element into the viewport
cy.scrollTo(position) Scroll the window/element to a position
.trigger(event) Dispatch a raw DOM event
.focus() / .blur() Focus / blur an element
.submit() Submit a form
.press(key) Dispatch a real keyboard key press (e.g. Cypress.Keyboard.Keys.TAB)
cy.get('input[name="q"]').type('cypress{enter}')
cy.get('#terms').check()
cy.get('select#country').select('Canada')
cy.get('input[type=file]').selectFile('cypress/fixtures/avatar.png')
cy.get('button.submit').click({ force: true })   // bypass actionability checks

Warning

Action commands enforce actionability: the element must exist, be visible, not be disabled, not be covered, and not be animating. If an action fails with "element is not visible" or "covered by another element", fix the app state or use { force: true } deliberately — force skips these safety checks.

5.4 Navigation

Command Description
cy.visit(url) Visit a URL (relative URLs resolve against baseUrl)
cy.reload() Reload the page (cy.reload(true) forces from server, not cache)
cy.go(direction) Navigate 'back' / 'forward', or by number
cy.visit('/dashboard')          // resolves against baseUrl
cy.go('back')
cy.reload()

5.5 Location & window

cy.url(), cy.hash(), cy.location(), cy.window(), cy.document(), cy.title(), cy.viewport(width, height).

cy.url().should('include', '/checkout')
cy.title().should('eq', 'My App')
cy.viewport(375, 667)            // simulate an iPhone-sized viewport
cy.window().its('myAppStore').should('exist')

5.6 Assertions

Assert with .should() and .and() using Chai/Chai-jQuery/Sinon-Chai chainers. You can also drop into an explicit callback with expect.

cy.get('.todo').should('have.length', 3)
cy.get('a.link')
  .should('have.attr', 'href')
  .and('include', 'cypress.io')

// callback form for complex assertions
cy.get('.list li').should(($li) => {
  expect($li).to.have.length(3)
  expect($li.eq(0)).to.contain('first')
})

Common chainers: have.length, have.text, contain, have.value, have.attr, have.class, be.visible, exist / not.exist, be.checked, be.disabled, have.css, match.

Note

.should('not.exist') is the correct way to assert an element is gone. .should('not.be.visible') asserts it exists but is hidden. They are different — pick deliberately.

5.7 Connectors & subject management

Command Description
.then(fn) Yield the subject into a callback (work with real values)
.each(fn) Iterate over an array-like subject
.spread(fn) Spread an array subject into callback arguments
.its(path) Get a property of the subject (retried)
.invoke(fn) Call a function on the subject (retried)
.wrap(value) Wrap any value so it can be chained / asserted
.as(alias) Alias the subject for later reuse via @alias
cy.wrap({ name: 'Jane' }).its('name').should('eq', 'Jane')
cy.get('.price').invoke('text').then((txt) => Number(txt.replace('$', '')))
cy.get('button').as('saveBtn')
cy.get('@saveBtn').click()

5.8 Network, requests & tasks

Command Description
cy.intercept(...) Spy on or stub network requests (see §8)
cy.request(...) Make an HTTP request outside the browser (no stubbing applies)
cy.wait('@alias') Wait for an intercepted request to complete
cy.exec(cmd) Run a system command (Node side)
cy.task(name, arg) Invoke a Node task registered in setupNodeEvents
cy.request('POST', '/api/seed', { users: 3 }).its('status').should('eq', 200)
cy.exec('npm run db:reset')
cy.task('queryDb', 'SELECT * FROM users')   // task defined in setupNodeEvents

Important

cy.request() runs from Cypress's Node process, not the browser — it is not affected by cy.intercept() and does not carry the browser's cookies automatically. Use it to seed data and hit APIs directly; use cy.visit + cy.intercept to test the app's own requests.

5.9 Files, fixtures & storage

cy.fixture(path), cy.readFile(path), cy.writeFile(path, contents), cy.getCookie/cy.getCookies/cy.getAllCookies, cy.setCookie, cy.clearCookie/cy.clearCookies/cy.clearAllCookies, cy.getAllLocalStorage/cy.clearLocalStorage/cy.clearAllLocalStorage, cy.getAllSessionStorage/cy.clearAllSessionStorage.

cy.fixture('user.json').then((user) => {
  cy.get('#name').type(user.name)
})
cy.setCookie('token', 'abc123')
cy.clearAllLocalStorage()

Caution

When setting a cookie with sameSite: 'no_restriction' (sent as SameSite=None), you must also set secure: true, or Cypress throws an error. Cookie name prefixes __Secure- and __Host- likewise enforce their browser rules.

5.10 Stubs, spies & clock

Command Description
cy.stub() Create a Sinon stub (replace a function)
cy.spy() Create a Sinon spy (observe a function)
cy.clock() Take control of Date, setTimeout, setInterval, etc.
cy.tick(ms) Advance the controlled clock
cy.clock()
cy.visit('/')
cy.tick(60_000)                  // fast-forward 60s of timers
cy.window().then((win) => {
  const onClick = cy.stub().as('onClick')
  win.addEventListener('click', onClick)
})

5.11 Sessions & multi-origin

Command Description
cy.session(id, setup, options?) Cache and restore browser session state (cookies, localStorage) across tests
cy.origin(url, fn) Run commands against a different origin (cross-domain)
// Log in once, reuse the session across every test
beforeEach(() => {
  cy.session('user', () => {
    cy.visit('/login')
    cy.get('#user').type('jane')
    cy.get('#pass').type('secret{enter}')
    cy.url().should('include', '/dashboard')
  })
})

// Interact with a third-party login on another domain
cy.origin('https://auth.example.com', () => {
  cy.get('#email').type('[email removed]')
  cy.get('#continue').click()
})

Tip

cy.session() is the recommended way to handle authentication. It runs the setup once, caches the resulting session, and restores it for subsequent tests — dramatically faster than logging in through the UI in every test.

5.12 Debugging & misc

cy.debug(), cy.pause(), cy.log(message), cy.screenshot(), Cypress.env(), cy.wait(ms | '@alias').

cy.pause()                       // pause execution; step through in the App
cy.get('.thing').debug()         // log the subject to devtools
cy.log('about to submit')
cy.screenshot('after-login')

6. Configuration

Set these in cypress.config.js. Values listed are the defaults read from Cypress's source.

6.1 Timeouts

Option Default Purpose
defaultCommandTimeout 4000 ms to retry most commands/assertions
requestTimeout 5000 ms to wait for cy.request / intercept request stage
responseTimeout 30000 ms to wait for a response
pageLoadTimeout 60000 ms to wait for cy.visit / page transitions
execTimeout 60000 ms for cy.exec
taskTimeout 60000 ms for cy.task

6.2 Viewport & behavior

Option Default (E2E) Purpose
viewportWidth 1000 Default browser viewport width (px)
viewportHeight 660 Default browser viewport height (px)
baseUrl null Prefix for relative cy.visit / cy.request URLs
scrollBehavior 'top' How elements are scrolled before actions
waitForAnimations true Wait for animations to finish before acting
animationDistanceThreshold 5 px movement that still counts as "animating"
keystrokeDelay 0 ms between simulated keystrokes
includeShadowDom false Traverse into shadow roots by default

6.3 Retries, isolation & test data

Option Default Purpose
retries { runMode: 0, openMode: 0 } Automatic test retries per mode
testIsolation true Reset browser state before each test (E2E)
numTestsKeptInMemory 50 Snapshots/command data kept in memory
watchForFileChanges true Re-run specs on file change in open mode

6.4 Artifacts

Option Default Purpose
video false Record a video of the run
videoCompression false Compress recorded video (CRF value or false)
videosFolder cypress/videos Output folder for videos
screenshotOnRunFailure true Auto-screenshot on test failure in run mode
screenshotsFolder cypress/screenshots Output folder for screenshots
trashAssetsBeforeRuns true Clear old screenshots/videos before each run

6.5 Network & security

Option Default Purpose
chromeWebSecurity true Chrome same-origin web security (set false for cross-origin in Chromium)
blockHosts null Glob list of hosts to block (e.g. analytics)
modifyObstructiveCode true Strip frame-busting code from responses
userAgent null Override the browser User-Agent
redirectionLimit 20 Max redirects to follow
clientCertificates [] Per-URL client certificate config

6.6 Spec & support patterns

Option Default Purpose
specPattern cypress/e2e/**/*.cy.{js,jsx,ts,tsx} (E2E) Where specs are found
excludeSpecPattern *.hot-update.js (E2E) Specs to ignore
supportFile cypress/support/e2e.{js,jsx,ts,tsx} File run before every spec
fixturesFolder cypress/fixtures Fixture data folder
downloadsFolder cypress/downloads Download target folder
reporter 'spec' Mocha reporter for cypress run
projectId null Cypress Cloud project ID (for recording)

6.7 Per-test and per-suite overrides

Override config inline with Cypress.config() or a config object:

describe('mobile', { viewportWidth: 375, viewportHeight: 667 }, () => {
  it('renders the mobile menu', { defaultCommandTimeout: 8000 }, () => {
    // ...
  })
})

6.8 Environment variables

Pass data into tests via env. Read it with Cypress.env('KEY').

// cypress.config.js
module.exports = defineConfig({ env: { apiUrl: 'http://localhost:4000' } })
cy.request(`${Cypress.env('apiUrl')}/users`)

Set or override env values from outside:

# via CLI flag
npx cypress run --env apiUrl=https://staging.example.com,grepTags=@smoke

# via OS environment (CYPRESS_ prefix)
CYPRESS_apiUrl=https://staging.example.com npx cypress run

Note

OS variables prefixed with CYPRESS_ (e.g. CYPRESS_BASE_URL, CYPRESS_apiUrl) are automatically picked up and stripped of the prefix. This is the standard way to inject secrets and per-environment values in CI.

6.9 Experimental options

Cypress exposes opt-in experiments (all default false unless noted):

experimentalCspAllowList, experimentalInteractiveRunEvents, experimentalRunAllSpecs, experimentalMemoryManagement, experimentalModifyObstructiveThirdPartyCode, experimentalOriginDependencies, experimentalSourceRewriting, experimentalSingleTabRunMode, experimentalWebKitSupport, experimentalFastVisibility, experimentalStudio, injectDocumentDomain.

Warning

Experimental options can change behavior or be removed between releases. Enable them deliberately and pin your Cypress version when you rely on one.


7. Running Tests from the CLI

Cypress has two run modes: the interactive App (cypress open) and headless/CI runs (cypress run).

7.1 cypress open — interactive

npx cypress open
Flag Purpose
-e, --env <env> Set environment variables
-c, --config <config> Override config values inline
-C, --config-file <path> Use a non-default config file
-b, --browser <name|path> Pre-select a browser
--e2e / --component Launch straight into a testing type
-P, --project <path> Path to a project root
--global Run the App in global mode
-p, --port <port> Port to run Cypress on
-d, --detached Run detached from the terminal

7.2 cypress run — headless / CI

npx cypress run
====================================================================================================
  (Run Starting)
  ┌────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:    14.x.x                                                                            │
  │ Browser:    Electron 130 (headless)                                                           │
  │ Specs:      3 found (login.cy.js, todo.cy.js, search.cy.js)                                   │
  └────────────────────────────────────────────────────────────────────────────────────────────┘
  ✓ All specs passed!                        00:42        12       12        -        -        -

Key flags:

Flag Purpose
-s, --spec <glob> Run only matching specs
-b, --browser <name|path> Choose browser (chrome, firefox, edge, electron)
--headed / --headless Show or hide the browser window
--e2e / --component Choose testing type
-c, --config / -C, --config-file Override config / use a different config file
-e, --env <env> Set environment variables
-r, --reporter <name> Mocha reporter (e.g. junit, mocha-junit-reporter)
-o, --reporter-options <opts> Reporter options
-q, --quiet Suppress Cypress output (reporter only)
--no-exit Keep the browser open after the run finishes
--pass-with-no-tests Exit 0 even if no specs are found
-p, --port <port> Run on a specific port
-P, --project <path> Project root path

Cloud-recording / parallelization flags:

Flag Purpose
--record [bool] Record results to Cypress Cloud
-k, --key <record-key> Cloud record key
--parallel Run specs in parallel across machines (requires --record)
--group <name> Group runs in the Cloud dashboard
--ci-build-id <id> Identify a CI build for grouping/parallel
-t, --tag <tag> Tag a recorded run
--auto-cancel-after-failures <n|false> Auto-cancel a recorded run after N failures
# Run a single spec in Chrome, headed
npx cypress run --spec "cypress/e2e/login.cy.js" --browser chrome --headed

# Record to Cypress Cloud in parallel
npx cypress run --record --key <record-key> --parallel --group "ci"

Note

cypress run always runs headless by default and exits with a non-zero code if any test fails — exactly what you want in CI. Add --headed only for debugging.

7.3 Supported browsers

Cypress detects locally installed browsers and bundles its own. Out of the box it supports Electron (bundled), Chrome, Chromium, Chrome Beta/Canary, Edge, and Firefox. WebKit (Safari's engine) is available behind experimentalWebKitSupport.

npx cypress run --browser chrome
npx cypress run --browser firefox
npx cypress run --browser /path/to/custom/chrome   # by absolute path

8. Network Stubbing with cy.intercept

cy.intercept() is Cypress's full-featured network layer — spy on requests, stub responses, and assert on traffic.

8.1 Spying (observe, don't change)

cy.intercept('GET', '/api/users').as('getUsers')
cy.visit('/users')
cy.wait('@getUsers').its('response.statusCode').should('eq', 200)

8.2 Stubbing (replace the response)

// Static stub from a fixture
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers')

// Inline stub body + status
cy.intercept('POST', '/api/login', {
  statusCode: 401,
  body: { error: 'Invalid credentials' },
}).as('login')

cy.visit('/login')
cy.get('#submit').click()
cy.wait('@login')
cy.get('.error').should('contain', 'Invalid credentials')

8.3 Dynamic handling

cy.intercept('GET', '/api/cart', (req) => {
  req.headers['x-test'] = 'true'      // modify the outgoing request
  req.reply((res) => {
    res.body.items.push({ id: 99 })   // modify the response
  })
})

8.4 Route matchers

The first argument can be a method + URL, a URL/glob, or a RouteMatcher object:

cy.intercept({ method: 'POST', url: '**/api/**', headers: { 'content-type': 'application/json' } }, handler)
cy.intercept('/assets/*.png', { statusCode: 404 })   // block images

Tip

Always wait on the alias (cy.wait('@alias')) before asserting on app state that depends on a request. This synchronizes your test with the network instead of guessing with cy.wait(ms).


9. Component Testing

Component testing mounts a single UI component in a real browser without a full app. Cypress ships first-party adapters as separate packages.

Framework Package Dev servers
React @cypress/react Vite, Webpack
Vue @cypress/vue Vite, Webpack
Angular @cypress/angular (+ @cypress/angular-zoneless) Angular CLI/Webpack
Svelte @cypress/svelte Vite, Webpack

Configure the testing type and dev server in cypress.config.js:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  component: {
    devServer: {
      framework: 'react',
      bundler: 'vite',
    },
  },
})

Write a component spec with cy.mount():

// Button.cy.jsx
import Button from './Button'

describe('<Button />', () => {
  it('calls onClick', () => {
    const onClick = cy.stub().as('onClick')
    cy.mount(<Button label="Save" onClick={onClick} />)
    cy.get('button').should('have.text', 'Save').click()
    cy.get('@onClick').should('have.been.calledOnce')
  })
})

Note

Register cy.mount once in cypress/support/component.js by re-exporting the framework's mount function (the scaffolder does this for you when you choose Component Testing in the App).

The component-testing defaults differ from E2E: viewportWidth/viewportHeight default to 500×500, slowTestThreshold to 250 ms, and the support/spec patterns point at component.* files.


10. Reusable Test Code

10.1 Custom commands

Add your own cy.* commands in the support file:

// cypress/support/commands.js
Cypress.Commands.add('login', (user, pass) => {
  cy.session([user, pass], () => {
    cy.request('POST', '/api/login', { user, pass })
      .its('body.token')
      .then((token) => window.localStorage.setItem('token', token))
  })
})

// usage in any spec
cy.login('jane', 'secret')

10.2 Node tasks

Run Node-side code (DB queries, file ops) via cy.task. Register in setupNodeEvents:

// cypress.config.js
module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('task', {
        resetDb() {
          // runs in Node, not the browser
          return null
        },
      })
    },
  },
})
cy.task('resetDb')

10.3 Fixtures

Store static data under cypress/fixtures/ and load it with cy.fixture():

cy.fixture('users.json').as('users')
cy.intercept('GET', '/api/users', { fixture: 'users.json' })

11. Continuous Integration

Cypress runs in any CI provider. The essentials:

# Typical CI command
npx cypress run --browser chrome

A minimal GitHub Actions workflow:

name: e2e
on: push
jobs:
  cypress:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npx cypress run --browser chrome

CI checklist:

  • [ ] Node >= 22.19.0 available on the runner
  • [ ] npm ci installs cypress and triggers the binary download
  • [ ] Cache the Cypress binary directory (~/.cache/Cypress on Linux) between builds
  • [ ] Start your app (or set baseUrl to a deployed URL) before cypress run
  • [ ] On Linux without a display, Cypress auto-launches a virtual framebuffer (Xvfb)

Tip

Cypress detects CI automatically via the CI environment variable. To record and parallelize, sign up for Cypress Cloud, set a projectId in your config, and run cypress run --record --key <key> --parallel.


12. Troubleshooting

Error: Impossible options: both headless and headed are true

Cause: You passed both --headed and --headless to cypress run. Solution: Pass only one. cypress run is headless by default; add --headed only to see the browser. Prevention: Don't combine the two flags in CI scripts.

Error: Cannot start. Invalid mode:

Cause: Cypress was launched with an unrecognized run mode (usually a malformed CLI invocation or wrapper script). Solution: Use cypress open or cypress run exactly; check for typos in custom npm scripts.

Error: Server#open called without config.baseUrl / "Cypress could not verify that this server is running"

Cause: You set or used a baseUrl that points at a server that isn't up yet (community issue #27990). Solution: Start your application before running Cypress, or wait for the port (e.g. with start-server-and-test). Confirm baseUrl matches the actual host/port. Prevention: Use start-server-and-test (or your CI's wait step) so Cypress only starts once the app responds.

Error: read ECONNRESET during a fresh npm install

Cause: Network/proxy interruption while downloading the Cypress binary (community issue #14175). Solution: Retry the install; configure HTTP_PROXY/HTTPS_PROXY; or set CYPRESS_DOWNLOAD_MIRROR to a reachable mirror. Behind a corporate proxy, set CYPRESS_DOWNLOAD_USE_CA=1 to use your CA bundle. Prevention: Cache the binary in CI and pin the Cypress version.

open hangs in an unconfigured monorepo with --e2e

Cause: Running cypress open --e2e in a workspace that has no Cypress config yet (community issue #29544). Solution: Run cypress open without --e2e first so the App can scaffold config interactively, then re-run.

Element is "not visible" / "covered by another element"

Cause: Cypress's actionability checks failed — the element is hidden, off-screen, disabled, or under an overlay. Solution: Assert the app reaches the right state first (.should('be.visible')), close the obstructing overlay, or use { force: true } when you intentionally want to bypass the check. Prevention: Wait on the meaningful state, not a fixed delay.

Tests pass in headed but fail in headless Electron

Cause: Timing/rendering differences, or features that behave differently headless (community issue #31068, around video + headless Electron). Solution: Reproduce with --browser electron --headless, add assertions instead of waits, and try --browser chrome to isolate whether it's Electron-specific.

cy.session() or cross-origin restore hangs

Cause: Sub-resource requests through the proxy timing out, especially with WebKit (community issue #33926). Solution: Ensure all origins the test touches are reachable; use cy.origin() for third-party domains; avoid relying on slow third-party scripts during session setup.

Important

When a command fails, open the Command Log in the App and click the failing step. Cypress shows a DOM snapshot from the moment of failure plus the console output (consoleProps) — this is usually faster than re-reading code.


13. Frequently Asked Questions

Q: Why can't I store a command's return value in a variable? Commands are asynchronous and enqueued. Use .then((subject) => { ... }) to access yielded values, or alias with .as('name') and retrieve via cy.get('@name').

Q: How do I wait for an API call instead of using cy.wait(2000)? Alias the request with cy.intercept(...).as('x') then cy.wait('@x'). Cypress waits exactly as long as the request takes.

Q: Does Cypress support multiple tabs or windows? No. Cypress runs in a single browser tab by design. Test the behavior behind a target="_blank" link by removing the target or asserting on the href, and use cy.origin() for cross-domain flows.

Q: How do I test login without going through the UI every time? Use cy.session() to run login once and restore the cached session for each test. Combine with cy.request() to authenticate via API for speed.

Q: What's the difference between cy.request() and cy.intercept()? cy.request() makes an HTTP call from Node, bypassing the browser and any stubs — great for seeding data. cy.intercept() observes/stubs the requests your application makes from the browser.

Q: How do I run only one test or spec? Use it.only(...) / describe.only(...) in code, or cypress run --spec "path/to/file.cy.js" from the CLI.

Q: How do I run Cypress in TypeScript? Name your specs *.cy.ts and your config cypress.config.ts. Cypress transpiles TypeScript automatically; no extra setup is needed for basic use.

Q: Where is the downloaded Cypress binary stored? In a global per-version cache. Print the path with npx cypress cache path, list versions with npx cypress cache list --size.

Q: How do I skip the binary download in Docker? Set CYPRESS_INSTALL_BINARY=0 during npm install, then provide the binary (e.g. a prebuilt cypress/included image) or run npx cypress install later.

Q: Can I retry flaky tests automatically? Yes. Set retries in config, e.g. retries: { runMode: 2, openMode: 0 } to retry failing tests up to twice in cypress run.

Q: How do I block analytics or third-party hosts? Use the blockHosts config option with a glob list, e.g. blockHosts: ['*.google-analytics.com'].

Q: My component test viewport is tiny — why? Component testing defaults to a 500×500 viewport (different from E2E's 1000×660). Set viewportWidth/viewportHeight in the component config block or per-test.

Q: How do I see why an element wasn't found? Cypress retries until defaultCommandTimeout. Increase it for a specific command (cy.get(sel, { timeout: 10000 })) or globally, and check the Command Log snapshot for what the DOM looked like.

Q: Is there a way to grep/filter tests by tag? Yes — the bundled @cypress/grep plugin lets you filter by title or tag (e.g. --env grep=@smoke).

Q: How do I take a screenshot or video manually? cy.screenshot('name') captures on demand. Set video: true in config to record full runs to videosFolder.


14. Quick Reference

Most-used commands

cy.visit('/path')                       // load a page
cy.get('[data-cy="x"]')                 // query an element
cy.contains('text')                     // query by text
cy.click() / cy.type('...') / cy.clear()// interact
cy.should('be.visible')                 // assert (auto-retried)
cy.intercept('GET', '/api', ...).as('a')// stub/spy network
cy.wait('@a')                           // wait on a request
cy.session(id, setupFn)                 // cache login
cy.fixture('data.json')                 // load test data
cy.task('name', arg)                    // run Node code

CLI cheat sheet

npx cypress open                        # interactive App
npx cypress run                         # headless CI run
npx cypress run --spec "**/login.cy.js" --browser chrome
npx cypress run --record --key KEY --parallel
npx cypress verify                      # verify binary
npx cypress info                        # environment info
npx cypress cache list --size           # cached versions
npx cypress install --force             # reinstall binary

Key config defaults

Option Default
defaultCommandTimeout 4000 ms
pageLoadTimeout 60000 ms
viewportWidth × viewportHeight 1000 × 660 (E2E)
retries { runMode: 0, openMode: 0 }
testIsolation true
video false
screenshotOnRunFailure true