mrkeyoor.com_
Wed 05 Aug 05:04 UTC
npmTestingupdated 05 Aug 2026

cypress

End-to-end and component testing framework that runs your tests inside a real browser, alongside your app, instead of driving the browser over a remote protocol. The npm package is only a launcher: a postinstall step downloads a several-hundred-megabyte Electron-bundled binary containing the runner, an interactive GUI with time-travel debugging, network stubbing via cy.intercept, and automatic waiting that removes most explicit sleeps from tests.

Verdict

Best-in-class developer experience for single-origin apps in Chrome, and the interactive runner is still unmatched. But Playwright has erased most other advantages while avoiding the browser, tab, and paid-parallelization limits, so compare hard before committing a new project.

API stability4/5The cy.* command API barely changes across majors; majors arrive often (v15 current) but migrations are mostly config-level, not test rewrites
Docs5/5docs.cypress.io is one of the best documentation sites in the JS ecosystem: task-oriented guides, runnable examples, and honest trade-off pages
Maintenance4/5Backed by the Cypress company with daily pushes and steady releases; the flip side is roughly 1,100 open issues and PRs
Ecosystem4/57.4M weekly downloads, 50k stars, a large plugin catalog and CI integrations; community momentum has visibly shifted toward Playwright

Use it if

  • You want an interactive runner with time-travel debugging that front-end developers actually enjoy using
  • Your app is a single-origin web app tested mainly in Chrome-family browsers or Firefox
  • You want network stubbing (cy.intercept) and automatic retry/waiting semantics instead of hand-written waits
  • You want component tests for React, Vue, or Angular in the same tool as your end-to-end suite
Skip it if

Setup reality

npm install cypress --save-dev then npx cypress open scaffolds config and example specs in a few minutes. The install itself is the first annoyance: a large binary lands in a system cache directory, so CI must persist that cache or every run re-downloads it. Config lives in cypress.config.js with separate e2e and component blocks. Budget real time for learning the command-queue model (no async/await), adding data-cy attributes for stable selectors, and triaging flake on animation-heavy pages.

Patterns

Visit a page and assert on contentvisit-and-assert

describe('home page', () => {
  it('shows the headline', () => {
    cy.visit('/');
    cy.contains('h1', 'Welcome').should('be.visible');
  });
});

Assertions auto-retry until the default 4s timeout, so you rarely need explicit waits for rendering.

Select elements with data-cy attributesselect-by-data-attribute

// <button data-cy="submit-order">Buy</button>
cy.get('[data-cy="submit-order"]').click();

CSS classes and text change with styling and copy edits; dedicated data-cy attributes are the officially recommended selector strategy.

Stub an API response with cy.interceptstub-network

cy.intercept('GET', '/api/products*', { fixture: 'products.json' }).as('getProducts');
cy.visit('/shop');
cy.wait('@getProducts');
cy.get('[data-cy="product-card"]').should('have.length', 3);

Register intercepts before cy.visit or the first request can slip past the stub.

Wait for a real request and inspect itwait-for-request

cy.intercept('POST', '/api/orders').as('createOrder');
cy.get('[data-cy="submit-order"]').click();
cy.wait('@createOrder').its('request.body').should('include', { qty: 2 });

Waiting on an alias replaces arbitrary cy.wait(3000) sleeps, which are the top source of slow flaky suites.

Add a reusable custom commandcustom-command

// cypress/support/commands.js
Cypress.Commands.add('getByCy', (id) => cy.get(`[data-cy="${id}"]`));

// in a spec
cy.getByCy('submit-order').click();

TypeScript users must also declare the command on the Cypress.Chainable interface or specs will not compile.

Log in once and cache it across testslogin-session

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

beforeEach(() => cy.login('admin', 's3cret'));

cy.session caches cookies and storage between tests; logging in through the UI in every test is the classic suite-speed killer.

Run headless in CIrun-headless-ci

npx cypress run --browser chrome --spec 'cypress/e2e/checkout/**'

# record video + screenshots on failure are on by default;
# cache ~/.cache/Cypress between CI runs to skip the binary download

Without caching the Cypress binary directory, every CI run re-downloads hundreds of megabytes.

Mount a React component testcomponent-test

import Button from './Button';

it('fires onClick', () => {
  const onClick = cy.stub().as('click');
  cy.mount(<Button onClick={onClick}>Save</Button>);
  cy.contains('button', 'Save').click();
  cy.get('@click').should('have.been.calledOnce');
});

Component testing needs its own block in cypress.config.js with your bundler (vite or webpack) declared.

Pass environment config into testsenv-vars

// cypress.config.js
module.exports = {
  e2e: { baseUrl: 'http://localhost:3000' },
  env: { apiUrl: 'http://localhost:4000' },
};

// in a spec
cy.request(`${Cypress.env('apiUrl')}/health`);

// override at runtime: npx cypress run --env apiUrl=https://staging.example.com

Variables prefixed CYPRESS_ in the shell are picked up automatically with the prefix stripped.

Upload a file in a testfile-upload

cy.get('input[type="file"]').selectFile('cypress/fixtures/invoice.pdf');

// drag and drop variant
cy.get('[data-cy="dropzone"]').selectFile('cypress/fixtures/invoice.pdf', {
  action: 'drag-drop',
});

selectFile is built in since Cypress 9.3; the old cypress-file-upload plugin is no longer needed.

Alternatives

PackageRegistryPick it when
playwrightnpmMulti-browser including WebKit, multi-tab flows, and free parallel sharding
webdriverionpmStandards-based WebDriver automation, including mobile via Appium
selenium-webdrivernpmYou already run Selenium Grid infrastructure or need its language breadth