Faulty Checkout at 2 a.m. in São Paulo
A thunderstorm rattled the hostel windows while I screenshared with Priya in Mumbai. Our React storefront looked perfect locally, yet customers on staging couldn’t finish checkout—the “Pay Now” button vanished after login. We traced the issue to a routed modal state that only broke after multiple page transitions. Manual QA had missed the edge‑case, but one Cypress test (cy.login().then(cy.pay)
) would have caught it in seconds. By dawn the rain cleared, the test turned green, and I crashed knowing we’d never ship that regression again.
Why End‑to‑End Testing Matters Today
Component tests prove isolated logic, but real users string flows together: auth, cart, payment, confirmation. This comes in handy when testing page functionality such as drag and drop features. Modern React apps rely on client‑side routing and feature flags that can break only after a few clicks. Cypress 14.5.2 — released July 15 2025 docs.cypress.io—adds Test Replay and faster browser launch times, making full‑flow tests nearly as quick as unit suites. With JavaScript’s ever‑growing supply‑chain risks, running production‑like journeys in CI is the surest way to sleep through time‑zone hand‑offs.
Toolbelt at a Glance
Tool / Concept | One‑liner purpose |
---|---|
Cypress 14.5 | Full‑browser E2E & component runner; now with Test Replay. |
cypress-axe | Injects axe‑core for WCAG audits during tests. |
msw | Mock Service Worker—intercepts network calls. |
start-server-and-test | Spins up Vite/Next dev server before Cypress. |
CLI Command | What it does |
---|---|
npm i -D cypress | Installs Cypress 14.5.2 Yarn. |
npx cypress open | Launches interactive runner. |
npm i -D cypress-axe msw | Adds a11y checks & network mocks. |
npx cypress run --record | Executes headless tests & uploads traces. |
Concept Primer — Plain English
- Command‑Runner Hybrid: Cypress bundles Chromium; no Selenium grids.
- Time‑Travel: Each command snapshot lets you scrub DOM history.
- Network Control: Stub, alias, or wait on
cy.intercept()
to tame flaky APIs. - Deterministic Clock: Freeze timers with
cy.clock()
to stabilise animations.
Step‑by‑Step — First Test to CI Pass
1. Scaffold
npm i -D cypress
npx cypress open # generates cypress.config.* and /e2e folder
Update config for React Router SPA:
// cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:5173', // Vite dev
viewportWidth: 1280,
viewportHeight: 800,
},
});
2. Write a Happy‑Path Flow
// cypress/e2e/checkout.cy.ts
describe('checkout flow', () => {
beforeEach(() => cy.visit('/'));
it('lets a user pay for coffee', () => {
cy.findByRole('button', { name: /login/i }).click();
cy.loginByApi('demo@shop.test', 'secret'); // custom command
cy.findByRole('link', { name: /shop/i }).click();
cy.addItem('Colombian Beans');
cy.findByRole('button', { name: /cart/i }).click();
cy.findByRole('button', { name: /pay now/i }).click();
cy.url().should('include', '/success');
cy.findByText(/thanks for your purchase/i);
});
});
Line‑by‑line
- Testing‑Library Queries (
findByRole
) mimic real accessibility paths. loginByApi
skips UI overhead via an authenticated cookie.- Custom
addItem
command wraps selector soup for clarity.
3. Harden with Network Stubs
cy.intercept('POST', '/api/payment', { statusCode: 200 }).as('pay');
cy.findByRole('button', { name: /pay now/i }).click();
cy.wait('@pay').its('response.statusCode').should('eq', 200);
No more flaky Stripe sandbox calls in CI.
4. Add Accessibility Check
import 'cypress-axe';
beforeEach(() => {
cy.injectAxe();
});
it('has no a11y violations on checkout', () => {
cy.findByRole('button', { name: /pay now/i }).click();
cy.checkA11y(null, {
includedImpacts: ['critical', 'serious'],
});
});
Failures surface inline alongside DOM snapshots—perfect for async reviews.
5. Wire CI Script
// package.json
"scripts": {
"test:e2e": "start-server-and-test dev http://localhost:5173 'cypress run --record --key $CYPRESS_KEY'"
}
GitHub Actions spins up the Vite server, waits for port 5173, then runs Cypress headless in Electron and uploads videos.
Common Pitfalls & Fixes
- Flaky Animations
Loading spinners can shift DOM before assertion. Fix: wrap clicks incy.within()
or usecy.waitUntil
on network aliases. - State Leakage Between Tests
LocalStorage persists across specs. Fix: addcy.session()
or callcy.clearAllCookies()
inafterEach
. - Hard‑Coded IDs
Tests break after refactor. Fix: rely on semantic roles (button
,heading
) with accessible names; they change far less.
Remote‑Work Insight Box
Our distributed team from Mexico City to Madrid reviews Cypress Test Replay videos directly in PR comments. Seeing the exact DOM at failure time eliminates “works on my machine” ping‑pong, shaving days off asynchronous bug hunts.
Performance & A11y Checkpoints
- Run Parallel: Cypress Cloud detects spec files and parallelises across CI nodes—cut runtime by 60 % with two containers.
- Component vs. E2E Mix: Keep happy‑path E2E small (<10) and offload edge‑cases to RTL component tests for faster feedback.
- Video Compression: Default MP4 can bloat artifacts; set
videoCompression=32
to trim size without losing clarity. - Test Data Hygiene: Seed databases per run; stale IDs cause shadow records that only break on prod.
- Screenreader Paths: Combine
cypress-axe
with Lighthouse CI to ensure a11y isn’t an afterthought.
Optional Diagram Description
Imagine an SVG: Dev Laptop pushes to GitHub → CI Runner spins Vite Server → Cypress Parallel Pods execute specs, producing Videos & Test Replay artifacts → PR UI shows pass/fail badges and replay links. Arrows illustrate feedback loops across time zones.
Wrapping Up — Key Takeaways
- React E2E tests with Cypress 14.5 detect multi‑page regressions your unit suite can’t.
- Stub external APIs with
cy.intercept()
and keep tests deterministic. - Query elements by role to future‑proof selectors and mirror real users, including those using assistive tech.
- Parallel CI plus Test Replay speeds remote debugging across continents.
- Blend E2E, component, and a11y tests for a holistic, reliable pipeline.
Got your own Cypress war story or a trick that tamed flake? Share it in the comments and let’s keep our Latin American dev lifestyles async‑friendly and bug‑free. Also if you’re interest in unit testing, consider reading this article.