DS DevShelfHub Projects · AI tools
Cheatsheets / Cypress
Cheatsheet · Dev tooling

Cypress: E2E and Component Testing Reference Guide

By DevShelfHub

Commands, retry-ability, fixtures, intercepts, sessions, component testing, CI tips — the everyday Cypress 13+ surface.

115 items 8 min Commands Intercepts Retry

Start hereQuick start · 6 you’ll reach for daily

Open GUInpx cypress open
Run headlessnpx cypress run
Visitcy.visit("/")
Get by rolecy.findByRole("button")
Stub APIcy.intercept(url, fixture)
Wait for itcy.wait("@alias")

Target versions · paceVersions

Targets: cypress ≥ 13 node ≥ 18 @testing-library/cypress ≥ 10

Cypress 13 stabilised cy.session(), removed legacy cy.server()/cy.route(), and made component testing GA across React, Vue, Svelte, Angular. Config is TypeScript: cypress.config.ts with separate e2e and component blocks. cy.origin() handles cross-origin flows; cy.intercept() replaces everything network-related.

Install · configSetup

bash
# Install
npm i -D cypress
# Component testing also needs your framework adapter (auto-installed by the wizard):
#   @cypress/react / @cypress/vue / @cypress/svelte / etc.

# Open the GUI (first run sets up cypress.config.ts + folders)
npx cypress open

# Run headlessly
npx cypress run                              # all e2e specs
npx cypress run --browser chrome             # pick a browser
npx cypress run --component                  # component testing
npx cypress run --spec "cypress/e2e/auth/**" # path filter
npx cypress run --env tag=smoke              # custom env var
npx cypress run --record --key $CY_KEY       # to Cypress Cloud / Currents

# cypress.config.ts (minimum)
import { defineConfig } from "cypress";
export default defineConfig({
  e2e: {
    baseUrl: "http://localhost:3000",
    setupNodeEvents(on, config) { return config; },
  },
  component: {
    devServer: { framework: "react", bundler: "vite" },
  },
  video: false,
  retries: { runMode: 2, openMode: 0 },
});

# package.json scripts
{
  "scripts": {
    "e2e":       "cypress run",
    "e2e:open":  "cypress open",
    "e2e:ci":    "start-server-and-test dev http://localhost:3000 e2e"
  }
}

Folders · filesProject layout

cypress.config.tsSingle config — e2e, component, env, retries.
cypress/e2e/**/*.cy.tsE2E specs. Filename pattern is configurable.
cypress/component/**/*.cy.tsxComponent specs — mounted in a real browser.
cypress/fixtures/*.jsonStatic JSON loaded via cy.fixture() or in intercept.
cypress/support/e2e.tsLoaded before every E2E spec — global hooks, plugin imports.
cypress/support/commands.tsCustom Cypress.Commands.add() definitions.
cypress/downloads/ cypress/screenshots/ cypress/videos/Generated at runtime. .gitignore them.

cy.* chain basicsCommands & chains

Cypress commands are not promises — they enqueue work the runner executes serially. Don’t await them; chain with .then() if you need the value in JS.

cy.visit("/path") / cy.visit({ url, method, body })Load a page.
cy.reload()Force a fresh load.
cy.get("[data-testid=email]")CSS-style selector.
cy.contains("Sign in")Text query (regex allowed).
cy.findByRole("button", { name: /pay/i })Preferred Testing-Library queries by role/label.
cy.find(".child") / cy.parent() / cy.children()Walk the DOM.
cy.eq(0) / cy.first() / cy.last() / cy.nth(2)Subselect.
cy.click({ force: true }) / cy.dblclick() / cy.rightclick()Click. force skips actionability checks.
cy.type("hi{enter}")Type chars. Special keys in {}.
cy.clear() / cy.check() / cy.uncheck() / cy.select("Pro")Form inputs.
cy.trigger("mouseover")Synthesize a DOM event.
cy.then(($el) => ...)Yield the subject to JS land. Don’t mix await.
cy.wrap(value)Bring a plain value into the chain (e.g. fixture data).
cy.log("note")Annotation in the command log.

should / expectAssertions

cy.get(sel).should("be.visible")Default form — auto-retries until timeout.
.should("have.text", "Hi") / "contain.text", "i"Text equality / substring.
.should("have.value", "42") / "have.attr", "href", "/x"Form value / attribute.
.should("have.class", "active") / "have.css", "color", "rgb(...)"Class / computed style.
.should("exist") / "not.exist"Presence.
.should("have.length", 3) / "have.length.gte", 1Collection size.
.should("be.disabled") / "be.checked" / "be.focused"State chai-jquery matchers.
.should("deep.equal", { a: 1 })Deep value check (use after .then or on JSON).
.should(($el) => { expect($el).to.have.length(2); })Function form for multiple/complex assertions.
cy.location("pathname").should("eq", "/dashboard")URL assertion.
cy.title().should("match", /Dashboard/)Document title.
Assertions are retry-able: Cypress reruns the command + assertion until both pass or timeout expires. That’s why cy.get("...").should(...) beats cy.wait(500); cy.get("...").

intercept · wait · stubNetwork

cy.intercept("GET", "/api/items*").as("items")Spy — observe without modifying.
cy.intercept("GET", "/api/items*", { fixture: "items.json" })Stub with a fixture.
cy.intercept("POST", "/api/x", { statusCode: 500, body: { error } })Stub with literal response.
cy.intercept(req => { req.headers["X-Test"] = "1"; req.continue(); })Modify request, let it through.
cy.intercept("GET", "/api/x", req => { req.reply(res => { res.body.k = "v"; }); })Modify the real response.
cy.wait("@items").its("response.statusCode").should("eq", 200)Wait + assert on the captured XHR.
cy.wait(["@a","@b"])Wait on several in parallel.
cy.request("POST", "/api/login", body)Direct HTTP — not via the page. Use for seeding state.
cy.fixture("items.json").as("items")Load a fixture — reference via @items.
javascript
// cypress/e2e/cart.cy.ts
describe("cart", () => {
  beforeEach(() => {
    // Stub list endpoint with a fixture
    cy.intercept("GET", "/api/items*", { fixture: "items.json" }).as("items");

    // Stub mutation with an explicit response
    cy.intercept("POST", "/api/checkout", {
      statusCode: 201,
      body: { paid: 999, id: "ord_1" },
      delay: 200,                              // simulate latency
    }).as("checkout");

    cy.visit("/cart");
  });

  it("submits the order", () => {
    cy.wait("@items");                         // pause until request fires
    cy.findByRole("button", { name: /pay/i }).click();

    cy.wait("@checkout").its("request.body").should("deep.include", { items: [] });

    cy.findByText(/order placed/i).should("be.visible");
  });

  it("handles a 500 from checkout", () => {
    cy.intercept("POST", "/api/checkout", { statusCode: 500 }).as("fail");
    cy.findByRole("button", { name: /pay/i }).click();
    cy.wait("@fail");
    cy.findByText(/something went wrong/i).should("be.visible");
  });
});

log in once, reuseSessions & auth

cy.session(key, setup, { validate, cacheAcrossSpecs })Preferred Cache cookies + storage between tests/specs.
Cypress.Commands.add("login", () => cy.session(...))Wrap in a custom command. One-line login per test.
cy.getCookie("sid") / cy.setCookie("k","v")Direct cookie access.
cy.clearCookies() / cy.clearLocalStorage()Manual cleanup.
cy.origin("https://auth.example.com", () => { ... })Run commands on a different origin (OAuth IdPs).
cy.request("POST", "/api/login").its("body.token").as("token")API login — faster than UI for seeding.
javascript
// cypress/support/commands.ts
Cypress.Commands.add("login", (email: string, pwd: string) => {
  // cy.session caches cookies + localStorage between tests
  cy.session(
    [email, pwd],                              // key — re-login when it changes
    () => {
      cy.request("POST", "/api/login", { email, pwd })
        .its("body.token")
        .then((token) => window.localStorage.setItem("token", token));
    },
    {
      validate() {                             // confirm cached session still works
        cy.request("/api/me").its("status").should("eq", 200);
      },
      cacheAcrossSpecs: true,                  // share across spec files
    },
  );
});

declare global {
  namespace Cypress {
    interface Chainable { login(email: string, pwd: string): Chainable; }
  }
}

// In a test
beforeEach(() => {
  cy.login("user@x.com", "pw");
  cy.visit("/dashboard");                      // already authed
});

extend cy.*Custom commands & tasks

Cypress.Commands.add("name", fn)Add a top-level command. Lives in support/commands.ts.
Cypress.Commands.add("name", { prevSubject: true }, (subj, args) => ...)Child command on a subject.
Cypress.Commands.overwrite("visit", (orig, url, opts) => orig(url, opts))Decorate an existing command.
cy.task("seedDb", payload)Run Node code inside setupNodeEvents — e.g. DB seed, file write.
Cypress.env("API_URL")Read env from config.env, CYPRESS_*, or --env.
declare namespace Cypress { interface Chainable { ... } }Type custom commands.

mount in real browserComponent testing

import { mount } from "cypress/react"Mount adapter (also cypress/vue, cypress/svelte, etc.).
cy.mount(<Counter initial={3} />)Render a component into the test runner.
component: { devServer: { framework: "react", bundler: "vite" } }Config block. Uses your real bundler.
cypress run --componentHeadless CT run.
cy.mount(<App />, { routerProps: { initialEntries: ["/x"] } })Per-framework options (router wrapping, store).
cy.stub(api, "fetchUser").resolves({ id: 1 })Stub a module method exactly as in unit tests.

read · uploadFiles & uploads

cy.readFile("data/x.json")Read from project root — retries until exists.
cy.writeFile("out/log.txt", "hi")Write a file (Node side).
cy.get("input[type=file]").selectFile("cypress/fixtures/x.png")Real file upload.
cy.get("a[download]").click(); cy.readFile("cypress/downloads/x.csv")Verify a download landed.
downloadsFolder: "cypress/downloads"Config option — folder is purged each run.

cypress.config.ts keysConfig & retries

baseUrl: "http://localhost:3000"Lets you use cy.visit("/") with no host.
viewportWidth / viewportHeightDefault device size.
defaultCommandTimeout: 4000Per-command retry window (ms). Bump for slow apps, not per-command.
pageLoadTimeout: 60_000 / requestTimeout: 5000Other timeouts. Tune the slow one, not all.
retries: { runMode: 2, openMode: 0 }Auto-retry flaky tests in CI. Off in the GUI.
video: false / videoCompression: 32Disable video on CI for speed; or compress to save space.
screenshotOnRunFailure: trueAuto-capture failures. Stored in cypress/screenshots/.
experimentalStudio: true / experimentalRunAllSpecs: trueOpt-in features — read release notes first.
env: { API_URL: "..." }Test env vars (also via CYPRESS_API_URL).

flags you actually useCLI flags

cypress openLaunch the GUI (interactive dev loop).
cypress runHeadless, all specs. Default in CI.
--browser chrome|firefox|edge|electronPick a runner.
--spec "cypress/e2e/auth/**"Path filter (glob).
--component / --e2ePick testing type.
--headedShow the browser window during a run.
--record --key $CY_KEYUpload to Cypress Cloud / Currents / Sorry.
--parallel --ci-build-id $IDDistribute across machines (cloud-recorded runs).
--env tag=smoke,API_URL=...Inject env vars at run time.
--config defaultCommandTimeout=10000One-shot config override.
--reporter junit --reporter-options "mochaFile=results.xml"Mocha reporters (JUnit, JSON, etc.).

A full login specEnd-to-end · Login flow

Two tests — failure path with the real API, success path with a stub. Demonstrates intercept, wait, role queries, and URL assertions.

javascript
// cypress/e2e/login.cy.ts
describe("login", () => {
  beforeEach(() => {
    cy.intercept("POST", "/api/login").as("login");
    cy.visit("/login");
  });

  it("rejects bad password", () => {
    cy.findByLabelText(/email/i).type("user@x.com");
    cy.findByLabelText(/password/i).type("wrong{enter}");
    cy.wait("@login").its("response.statusCode").should("eq", 401);
    cy.findByRole("alert").should("contain.text", "Invalid");
  });

  it("logs in and redirects", () => {
    cy.intercept("POST", "/api/login", {
      statusCode: 200,
      body: { token: "abc" },
    }).as("login");

    cy.findByLabelText(/email/i).type("user@x.com");
    cy.findByLabelText(/password/i).type("right{enter}");

    cy.wait("@login");
    cy.location("pathname").should("eq", "/dashboard");
    cy.findByText(/welcome/i).should("be.visible");
    cy.window().its("localStorage.token").should("eq", "abc");
  });
});

Best practiceGood to know

Use data-testid or role queries, not CSS structure. Class names and DOM shape change with refactors; data-testid + findByRole survive them.
Let retry-ability do the waiting. cy.get(".x").should("be.visible") retries until success or timeout. cy.wait(500) is a smell.
Seed via cy.request(), exercise via UI. Logging in through the form for every test is slow and brittle. API-login + cy.session() is the standard pattern.

Common trapsWatch out for

Don’t await Cypress commands. They’re queue entries, not promises. const x = await cy.get(...) yields the chain object, not the element.
Variables don’t flow through the chain. let user; cy.request(...).then(r => user = r.body); /* user is still undefined here */ — use .as("user") + cy.get("@user").
Cross-origin navigation throws. Going to a different origin (auth IdP, third-party widget) requires cy.origin("https://...", () => ...), not a bare cy.visit().

Go deeperSee also

Cypress FAQ

What is Cypress used for?

Cypress is an end-to-end testing framework for web applications. It runs in the same process as the browser, giving you real-time access to the DOM, network requests, and application state. It supports both E2E tests that drive a full page and component tests that mount individual UI components.

Is Cypress better than Selenium?

Cypress is faster to set up and debug than Selenium because it runs in-process with the browser, has built-in automatic waiting, and comes with a time-travel debugger. Selenium is better when you need multi-tab control, cross-browser coverage beyond Chromium and Firefox, or non-JavaScript test runners.

Does Cypress support cross-origin testing?

Yes. Since Cypress 9.6, cy.origin() lets you navigate to a different domain in the same test and interact with it. You pass the origin as a string, then run commands inside the callback. The experimentalModifyObstructiveThirdPartyCode flag handles stubborn third-party auth pages.

How do I stub API calls in Cypress?

Use cy.intercept(method, url, response) to intercept and stub network requests. You can return a fixture file, an inline object, or a callback that modifies the real response. Always assign an alias with .as('alias') and wait on it with cy.wait('@alias') to synchronize the test.

Does Cypress support component testing?

Yes. Since Cypress 10, component testing is GA for React, Vue, Svelte, and Angular. Run cypress open --component or configure a separate component block in cypress.config.ts. Component tests mount a single component in a real browser without a server, giving fast, isolated feedback.

Is Cypress free and open source?

The Cypress test runner is MIT-licensed and free to use locally and in CI. Cypress Cloud (formerly Cypress Dashboard) is the paid SaaS product for parallelization, test recording, flake detection, and analytics — it has a limited free tier. All core testing functionality including component testing, network interception, and the Test Replay feature in recent versions is available without a subscription.