SoftwareTestPilot
Automation TestingPublished: Updated: · 1 week ago25 min read

Cypress Testing: Complete Beginner's Guide (2026 Step-by-Step)

Learn Cypress testing from scratch in 2026. Step-by-step beginner's guide covering installation, first test, locators, assertions, fixtures, custom commands, CI/CD, component testing, and the Cypress Dashboard.

Avinash Kamble
Avinash Kamble
Founder & QA Engineer at SoftwareTestPilot
Reviewed by Priyanka G.
Share:XLinkedInWhatsApp
Cypress testing complete beginner's guide cover — pillar tutorial covering install, commands, fixtures, network stubbing, component testing and CI/CD.
Cypress testing complete beginner's guide cover — pillar tutorial covering install, commands, fixtures, network stubbing, component testing and CI/CD.
In this article
  1. 1. Why Cypress in 2026
  2. 2. Install Cypress Step by Step
  3. 3. Your First Cypress Test
  4. 4. Locators and the Auto-Wait Magic
  5. 5. Assertions Deep Dive
  6. 6. Fixtures and Test Data
  7. 7. Custom Commands
  8. 8. Network Stubbing with cy.intercept
  9. 9. Hooks: Before, BeforeEach, After
  10. 10. Component Testing
  11. 11. Page Object Model in Cypress
  12. 12. Parallelization and the Cypress Dashboard
  13. 13. Running Cypress in CI/CD
  14. 14. Debugging and Time-Travel
  15. 15. Cypress Best Practices for 2026
  16. 16. Migrating From Selenium to Cypress (When It Makes Sense)
  17. 17. The Cypress Ecosystem in 2026
  18. 18. Cypress vs Playwright vs Selenium vs WebdriverIO (Honest 2026 Comparison)
  19. 19. Common Cypress Errors and How to Fix Them
  20. Next, level up your Cypress skills
  21. Frequently asked questions

Last updated: June 25, 2026 · Reading time: 25 minutes · By SoftwareTestPilot Editorial Team

What you'll learn: By the end of this Cypress testing tutorial you will have Cypress installed, your first test passing, network stubs working, component tests running, and a CI pipeline executing everything in headless mode — even if you have never written a single line of test code before.

1. Why Cypress in 2026

Cypress is a JavaScript end-to-end testing framework built for the modern web. Unlike Selenium, which drives the browser from outside, Cypress runs inside the same execution context as your application. That single architectural difference unlocks four superpowers:

  1. Auto-waiting — Cypress waits for elements, animations, network calls, and re-renders before acting. Tests rarely need cy.wait(2000).
  2. Time-travel debugging — hover over any command in the runner and see the DOM snapshot, network state, and console logs at that exact moment.
  3. Real-time reloads — save a file, see the test re-run instantly. The feedback loop is sub-second.
  4. Network control — stub any HTTP call with a one-liner to test edge cases that are hard to reproduce against a real backend.

The trade-offs are real: limited to Chrome/Edge/Firefox/WebKit, no multi-tab support, and a smaller community than Selenium. For new JavaScript front-end projects, those trade-offs are usually worth it. Compare deeper with Playwright.

2. Install Cypress Step by Step

Prerequisites

  • Node.js 18 LTS or 20 LTS — download from nodejs.org. (Node 22 is supported but Cypress has best stability on LTS.)
  • A code editor — VS Code is recommended.
  • A project — any web app or a fresh demo you want to test against.

Step 1 — Create a project folder

mkdir cypress-demo
cd cypress-demo
npm init -y

Step 2 — Install Cypress

npm install --save-dev cypress

This will download Cypress and its bundled browsers. It can take a few minutes the first time because Cypress downloads Electron, Chrome, Firefox, and WebKit.

Step 3 — Open the Test Runner

npx cypress open

Cypress creates a cypress/ folder, an initial cypress.config.js, and opens the Test Runner with example specs. Pick E2E TestingChrome and Cypress scaffolds a starter spec.

Step 4 — Verify the install

npx cypress run --browser chrome --spec "cypress/e2e/1-getting-started/todo.cy.js"

Tip: Cypress caches browsers in ~/.cache/Cypress. Cache that directory in your CI to shave minutes off every build.

3. Your First Cypress Test

Create cypress/e2e/login.cy.js:

describe('Login flow', () => {
  it('logs in with valid credentials', () => {
    cy.visit('https://example.com/login')
    cy.get('[data-testid="email"]').type('admin@example.com')
    cy.get('[data-testid="password"]').type('Sup3rSecret!')
    cy.get('[data-testid="submit"]').click()
    cy.url().should('include', '/dashboard')
    cy.contains('Welcome, admin').should('be.visible')
  })
})

What's happening:

  • describe groups related tests.
  • it is a single test case.
  • cy.visit opens the URL.
  • cy.get queries a DOM element.
  • .type, .click simulate user actions.
  • .should makes assertions.

Run it from the Test Runner or with npx cypress run. Cypress re-runs the test every time you save the file.

4. Locators and the Auto-Wait Magic

The single biggest Cypress mistake is using fragile XPath like /html/body/div[3]/form/input[1]. Use stable, semantic selectors instead.

PrioritySelectorExampleWhen to use
1data-testid[data-testid="submit"]Always preferred — explicitly added for tests, never restyled
2rolecy.getByRole('button', { name: 'Submit' })Best for accessibility and stability
3id#emailAcceptable but IDs often change
4CSS.btn-primaryFine for stable class names
5Textcy.contains('Sign in')Useful when text is part of the contract
6XPath//buttonAvoid unless no alternative

Cypress auto-waits up to 4 seconds (configurable) for each locator. There is no waitForElement; if the element does not appear, the test fails with a clear message.

import '@testing-library/cypress/add-commands'

cy.getByRole('button', { name: /submit/i }).click()
cy.getByLabelText('Email address').type('admin@example.com')
cy.getByTestId('password').type('Sup3rSecret!')

5. Assertions Deep Dive

Cypress bundles Chai and Sinon-Chai for assertions. The chainable .should() is the most common form.

cy.get('[data-testid="cart-count"]')
  .should('be.visible')
  .and('have.text', '3')
  .and('have.css', 'color', 'rgb(22, 163, 74)')

cy.get('[data-testid="submit"]').should('be.disabled')
cy.url().should('eq', 'https://example.com/dashboard')
cy.window().its('localStorage.user').should('exist')

Other useful assertions:

  • expect(value).to.deep.equal(expected) — deep object equality.
  • cy.get('.row').should('have.length', 12) — count.
  • assert.isAbove(response.duration, 0) — performance guard.

6. Fixtures and Test Data

Fixtures are static files in cypress/fixtures/ that hold deterministic test data. Use them for reusable, known-good data; use factories for unique-per-test data.

Step 1 — Create a fixture

Add cypress/fixtures/users.json:

[
  { "email": "admin@example.com", "role": "admin" },
  { "email": "user@example.com", "role": "viewer" }
]

Step 2 — Load it

cy.fixture('users.json').then((users) => {
  cy.login(users[0].email, 'Sup3rSecret!')
})

Step 3 — Use multiple data sets

cy.fixture('users.json').then((users) => {
  users.forEach((user) => {
    it(`logs in as ${user.role}`, () => {
      cy.login(user.email, 'Sup3rSecret!')
      cy.get('[data-testid="role"]').should('have.text', user.role)
    })
  })
})

7. Custom Commands

Custom commands turn repetitive sequences into reusable keywords, the Cypress equivalent of POM helper methods.

Define a command

Cypress.Commands.add('login', (email, password) => {
  cy.visit('/login')
  cy.get('[data-testid="email"]').type(email)
  cy.get('[data-testid="password"]').type(password)
  cy.get('[data-testid="submit"]').click()
  cy.url().should('include', '/dashboard')
})

Cypress.Commands.add('loginByRole', (role) => {
  cy.fixture('users.json').then((users) => {
    const user = users.find((u) => u.role === role)
    return cy.login(user.email, 'Sup3rSecret!')
  })
})

Use the command

beforeEach(() => {
  cy.loginByRole('admin')
})

Custom commands are typed automatically via JSDoc if you use TypeScript.

8. Network Stubbing with cy.intercept

cy.intercept is one of Cypress's killer features. You can stub any HTTP call to test edge cases that are hard to reproduce against a real backend.

Stub a response

cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers')
cy.visit('/users')
cy.wait('@getUsers')
cy.get('[data-testid="user-row"]').should('have.length', 2)

Modify a real response

cy.intercept('GET', '/api/profile', (req) => {
  req.reply((res) => {
    res.body.role = 'admin'
  })
})

Simulate latency and errors

cy.intercept('POST', '/api/orders', (req) => {
  req.reply({ statusCode: 500, body: { error: 'boom' } })
}).as('createOrder')

Wait on a real call

cy.intercept('POST', '/api/orders').as('createOrder')
cy.get('[data-testid="buy"]').click()
cy.wait('@createOrder').its('response.statusCode').should('eq', 201)

For advanced patterns see our API Testing Guide.

9. Hooks: Before, BeforeEach, After

Cypress provides Mocha-style hooks for setup and teardown.

describe('Orders', () => {
  before(() => { cy.seedDatabase() })
  beforeEach(() => { cy.loginByRole('admin') })
  afterEach(() => { cy.clearCookies() })
  after(() => { cy.resetDatabase() })

  it('creates an order', () => { /* ... */ })
  it('cancels an order', () => { /* ... */ })
})

Anti-pattern: Never put application state setup inside before() if you run tests in parallel — it will leak across files. Use beforeEach() for per-test isolation.

10. Component Testing

Cypress can mount individual React, Vue, Angular, or Svelte components in isolation and test them against props, events, and rendered output.

Install the component adapter

npm install --save-dev @cypress/react @cypress/webpack-dev-server

Write a component test

import Button from '../../src/components/Button'

describe('<Button />', () => {
  it('renders the label', () => {
    cy.mount(<Button label="Submit" />)
    cy.getByRole('button').should('have.text', 'Submit')
  })

  it('fires onClick', () => {
    const onClick = cy.stub()
    cy.mount(<Button label="Submit" onClick={onClick} />)
    cy.getByRole('button').click()
    cy.wrap(onClick).should('have.been.calledOnce')
  })
})

Component tests run in milliseconds and are the new bottom of the test pyramid for front-end teams.

11. Page Object Model in Cypress

POM keeps locators in one place so a UI change touches one file, not fifty.

export class LoginPage {
  visit() { cy.visit('/login') }
  fillEmail(email) { cy.get('[data-testid="email"]').clear().type(email) }
  fillPassword(password) { cy.get('[data-testid="password"]').clear().type(password) }
  submit() { cy.get('[data-testid="submit"]').click() }

  loginAs(email, password) {
    this.visit()
    this.fillEmail(email)
    this.fillPassword(password)
    this.submit()
  }
}
import { LoginPage } from '../support/pages/LoginPage'
const login = new LoginPage()

it('logs in', () => {
  login.loginAs('admin@example.com', 'Sup3rSecret!')
  cy.url().should('include', '/dashboard')
})

12. Parallelization and the Cypress Dashboard

Once your suite grows past ~5 minutes, parallelize.

Run Cypress in parallel

cypress run --parallel --record --key $CYPRESS_RECORD_KEY

Self-hosted parallelism

Split specs across machines manually using --spec "cypress/e2e/a/**/*.cy.js" on one runner and --spec "cypress/e2e/b/**/*.cy.js" on another, or use the open-source cypress-split plugin.

Cypress Dashboard

The Cypress Dashboard provides test replay (video + DOM snapshots), flake detection, load balancing of specs across runners, and historical analytics. The free tier covers up to 500 test results per month.

Tip: Cypress's Smart Orchestration balances specs by historical runtime, so slow specs do not bottleneck. Use it when you have more than 4 CI workers.

13. Running Cypress in CI/CD

GitHub Actions

name: Cypress Tests
on: [push, pull_request]
jobs:
  cypress:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - uses: cypress-io/github-action@v6
        with:
          browser: chrome
          record: true
        env:
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GitLab CI

cypress:
  image: cypress/included:14.0.0
  script:
    - cypress run --browser chrome --record --key $CYPRESS_RECORD_KEY
  artifacts:
    when: always
    paths:
      - cypress/videos
      - cypress/screenshots
    expire_in: 7 days

Jenkins

Use the official Cypress Jenkins plugin or call cypress run from a pipeline stage. Publish JUnit XML reports for trend graphs.

Heads up: Always cache ~/.cache/Cypress in CI to avoid re-downloading ~600 MB of browsers every run.

14. Debugging and Time-Travel

Time-travel

Open the Test Runner, hover any command in the command log — Cypress shows the DOM snapshot at that moment. Click to inspect the network request, console log, and cookies that were live then.

cy.pause and cy.debug

it('debugs a flow', () => {
  cy.visit('/login')
  cy.pause()
  cy.get('[data-testid="email"]').type('admin@example.com')
  cy.debug()
  cy.get('[data-testid="submit"]').click()
})

Console and logs

Use cy.log('arrived at dashboard') to add breadcrumbs that show in the runner.

Video and screenshots

Every headless run records a video and captures a screenshot on failure. They are stored in cypress/videos/ and cypress/screenshots/.

15. Cypress Best Practices for 2026

Do

  • Use data-testid attributes for selectors.
  • Test from the user's perspective, not implementation details.
  • Stub network calls with cy.intercept for speed and reliability.
  • Use the Page Object Model for any non-trivial app.
  • Run smoke on every PR, full suite nightly.
  • Set a 4–6 second defaultCommandTimeout — avoid silent 30s waits.
  • Use TypeScript for spec files to catch selector typos early.

Don't

  • Don't use cy.wait(2000) for synchronization.
  • Don't share state across tests via globals.
  • Don't test the same flow in many specs — one canonical spec per journey.
  • Don't rely on real third-party APIs in CI — stub them.

16. Migrating From Selenium to Cypress (When It Makes Sense)

You should migrate a Selenium suite to Cypress only when (a) your stack is JavaScript/TypeScript, (b) you primarily test in Chrome/Edge/Firefox/WebKit, and (c) the maintenance cost of the Selenium suite has grown faster than the value it delivers.

Phase 1 — Audit and freeze

Inventory every Selenium test. Tag each as keep, rewrite, drop. Anything that tests visual regression, complex file uploads, or native OS dialogs is usually a drop in Cypress.

Phase 2 — New tests in Cypress

All new end-to-end coverage goes into Cypress. Use POM in both suites temporarily to share business concepts.

Phase 3 — Decommission

Once coverage parity is reached (usually after 3–6 months), turn off the Selenium pipeline.

Common pitfall: Trying to convert Selenium tests 1:1 to Cypress tests. Cypress has different idioms — rewrite around Cypress's strengths.

17. The Cypress Ecosystem in 2026

ToolPurposeWhen to use
Cypress Cloud (Dashboard)Test Replay, flake analytics, smart orchestrationTeams with >5 CI workers and >200 specs
@cypress/reactComponent testing for ReactReplacing Jest + RTL for component-level E2E
@cypress/vueComponent testing for Vue 3Vue 3 component libraries
@cypress/angularComponent testing for AngularAngular component libraries
cypress-real-eventsReal native browser events (hover, swipe)When built-in .click() does not trigger app handlers
@testing-library/cypressRole and label locatorsAlways — huge accessibility win
cypress-axeAccessibility assertions (WCAG)Teams with a11y SLOs
cypress-image-diffVisual regressionReplacing Percy or Chromatic for free-tier teams

18. Cypress vs Playwright vs Selenium vs WebdriverIO (Honest 2026 Comparison)

DimensionCypressPlaywrightSeleniumWebdriverIO
First install to first green test~5 minutes~10 minutes~30 minutes~20 minutes
Auto-waitingNativeNativeManualManual
Time-travel debuggingYesYes (Trace Viewer)NoNo
Browser supportChrome, Edge, Firefox, WebKitChrome, Edge, Firefox, WebKit + mobileAll browsers + mobile + legacyAll + mobile
LanguagesJS / TS onlyJS, TS, Python, Java, .NETJava, C#, Python, Ruby, JS, KotlinJS, TS
Multi-tabNoYesYesYes
Component testingFirst-classYes (Playwright CT)NoNo
Native mobileNoExperimentalVia AppiumVia Appium
Best fitJS/TS front-end teamsPolyglot, mobile + webEnterprise, legacy, cross-languageWeb + mobile via Appium

2026 rule of thumb: pick Playwright for greenfield projects, pick Cypress for JS-only front-end teams that prize DX, pick Selenium when you need breadth (languages, browsers, mobile, legacy), pick WebdriverIO when you want Selenium ergonomics plus Appium in one runner.

19. Common Cypress Errors and How to Fix Them

1. Timed out after waiting 4000ms for your expected elements

Cause: Selector typo, wrong element, or element never renders. Fix: Run the test in headed mode, open DevTools, verify the selector. Add data-testid if brittle.

2. Cypress detected a cross-origin error

Cause: App navigates to a different origin mid-test (e.g., OAuth). Fix: Use cy.origin('https://oauth.provider.com', () => { ... }) or stub the redirect.

3. cy.visit() failed trying to load

Cause: Network failure, wrong URL, blocked by CORS, or auth redirect loop. Fix: Verify URL, check network tab, ensure auth cookies are set.

4. Cannot read property 'click' of undefined

Cause: cy.get(...) returned no element. Fix: Re-check selector; use cy.contains; add .should('exist') before the action.

5. cy.intercept() method mismatch

Cause: HTTP method mismatch in the stub. Fix: Match the actual method: cy.intercept('POST', '/api/orders', ...).

6. The test has finished but Cypress has not received any commands

Cause: Async operation without awaiting, or setTimeout instead of Cypress commands. Fix: Replace setTimeout with cy.wait; use .then() Promises.

7. Chromium failed to start

Cause: Docker / CI memory limits or missing libraries. Fix: Increase memory, install libgbm, libnss3, or run with --browser electron.

Next, level up your Cypress skills

Rehearse Cypress concepts live with the AI Mock Interview, polish your CV with the free Resume ATS Review, and join 11K+ testers in the QA Network for daily questions and referrals.

Frequently asked questions

Is Cypress better than Selenium?

It depends. Cypress wins on developer experience, speed, and built-in features for JavaScript teams. Selenium wins on language coverage (Java, C#, Python, Ruby, JavaScript), browser coverage (including Safari on real devices), and maturity in enterprise environments.

Does Cypress support Safari?

Yes — Cypress ships WebKit (Safari's engine). For real Safari on macOS or iOS, use a cloud grid such as BrowserStack or Sauce Labs.

Can Cypress test mobile apps?

Cypress tests web apps on mobile viewports and emulators via cy.viewport('iphone-x') and integrated device emulation. For native iOS or Android apps, use Appium.

How long does a Cypress test typically take?

A well-designed E2E test takes 1–5 seconds. Component tests run in 50–300 ms. A full suite of 200 E2E tests should finish in under 10 minutes when parallelized.

What's the difference between Cypress Studio and record-and-playback?

Cypress Studio lets you record interactions directly into a spec file and edit them — useful for prototyping. It is not recommended for production suites; hand-written POM-based specs are more maintainable.

Is Cypress parallel testing free?

Splitting specs manually with --spec or with the open-source cypress-split plugin is free. The Cypress Cloud orchestrated parallel mode is paid.

Should I learn Cypress in 2026?

Worth knowing if your team already uses it or you work on a JS/TS front-end. For a fresh learning bet across the broader job market, prioritize Playwright and Selenium.

Keep going

Practice these questions

Rehearse Selenium and Playwright automation questions covering framework design, waits, locators and CI/CD.

Found this useful?
Share:XLinkedInWhatsApp

Was this article helpful?

Keep building your QA edge

Continue reading

Join the QA Community

Connect with fellow testers, share job leads, and get career advice.

Premium QA Resources

Stop Reinventing the Wheel. Upgrade Your QA Arsenal.

Take your testing skills from beginner to Lead Engineer. Supercharge your daily workflow with our premium digital resources.

  • ⚡ Ready-to-use testing strategy templates
  • 🔥 Advanced API & UI automation guides
  • ⏱️ Save 10+ hours a week on test planning
4.9/5 rating
Explore All Products

⭐⭐⭐⭐⭐ Trusted by 1,000+ Software Test Pilots • Instant Access