# Cypress User Guide

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.

```bash
# 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
```

```text
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:

```javascript
// 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"

    ```bash
    npm install --save-dev cypress
    ```

=== "Yarn"

    ```bash
    yarn add --dev cypress
    ```

=== "pnpm"

    ```bash
    pnpm add --save-dev cypress
    ```

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

```text
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

```bash
npx cypress verify
```

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

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

```bash
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:

```bash
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

```bash
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`:

```javascript
// 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
    },
  },
})
```

```typescript
// 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

```javascript
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:

```javascript
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.

```javascript
// 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)`:

```javascript
// 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 |

```javascript
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`.

```javascript
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`) |

```javascript
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 |

```javascript
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)`.

```javascript
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`.

```javascript
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` |

```javascript
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` |

```javascript
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`.

```javascript
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 |

```javascript
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) |

```javascript
// 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')`.

```javascript
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:

```javascript
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')`.

```javascript
// cypress.config.js
module.exports = defineConfig({ env: { apiUrl: 'http://localhost:4000' } })
```

```javascript
cy.request(`${Cypress.env('apiUrl')}/users`)
```

Set or override env values from outside:

```bash
# 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

```bash
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

```bash
npx cypress run
```

```text
====================================================================================================
  (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 |

```bash
# 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`.

```bash
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)

```javascript
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)

```javascript
// 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

```javascript
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:

```javascript
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`:

```javascript
const { defineConfig } = require('cypress')

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

Write a component spec with `cy.mount()`:

```jsx
// 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:

```javascript
// 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`:

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

```javascript
cy.task('resetDb')
```

### 10.3 Fixtures

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

```javascript
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:

```bash
# Typical CI command
npx cypress run --browser chrome
```

A minimal GitHub Actions workflow:

```yaml
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

```javascript
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

```bash
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` |

---

_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. Unofficial; not affiliated with or reviewed by the project._
