Modern Frontend Testing with Cypress
Learn when to use Cypress end-to-end and component tests, how to set them up, and how to make browser test suites easier to debug and maintain.
Cypress helps frontend teams test JavaScript applications in a real browser. Use end-to-end (E2E) tests to verify critical user journeys through a running application, and component tests to check a component’s rendered behavior and appearance in isolation. The right level depends on what you need to validate: a component test cannot prove that a complete application journey works, while an E2E test covers more of the system and needs a running application.
The Cypress App is a free, open-source application installed locally in your project. Cypress Cloud is an optional SaaS companion for recording CI runs, debugging failures, analytics, and orchestration. Keep that distinction in mind when planning cost and deciding what belongs in local development versus a team CI workflow.
1. Choose the right testing level
| What you need to validate | Use | Why |
|---|---|---|
| A critical user journey through the browser and application | E2E | Exercises the application through browser interactions and can expose failures a user would encounter. |
| A component’s rendered output and interactions | Component testing | Mounts the component in a real browser for focused feedback without asserting that the whole application journey works. |
| A complete Next.js page that depends on server-only methods | E2E | Cypress recommends E2E for pages whose server-side methods would not run in a component test. |
| Recorded CI results, suite health, debugging, or orchestration | Cypress Cloud | Optional team service for teams that need those CI capabilities. |
Use both E2E and component tests when both scopes matter. Do not treat either as a universal replacement for other test levels. A practical starting point is a focused set of E2E tests for important journeys and component tests for behavior that benefits from fast, isolated feedback.
2. Install Cypress and open the App
Install Cypress as a project development dependency. Choose the package manager already used by your project:
# npm
npm install --save-dev cypress
# Yarn
yarn add --dev cypress
# pnpm
pnpm add --save-dev cypress
# Bun
bun add --dev cypress
Open the interactive Cypress App from the project directory:
npx cypress open
# or
yarn cypress open
# or
pnpm cypress open
# or
bunx cypress open
Select E2E Testing or Component Testing in the launcher and follow the setup prompts. The generated files depend on the selected testing type and project. For exact current setup instructions, use the official installation guide and the relevant component testing guide.
Browser and framework compatibility
Compatibility is version-sensitive. Cypress’s installation documentation lists the latest three major versions of Chrome, Edge, and Firefox. Firefox 141 and later require Cypress 14.1.0 or later according to that documentation. WebKit support is experimental. Cypress’s bundled Electron browser is deprecated and scheduled for removal in a future release, so select an installed Chrome, Edge, or Firefox browser rather than building a workflow around Electron.
Component testing depends on the combination of UI framework, framework version, and bundler. The current Cypress matrix includes maintained integrations for React, Vue, Angular, and Svelte, with specific framework and bundler qualifications; Svelte 5 with Vite or Webpack is marked alpha. Qwik and Lit entries are community integrations. Check the live support matrix before choosing a setup, especially when upgrading a framework or bundler.
3. Write an E2E test around user-visible behavior
For E2E testing, start your application server through your development or CI workflow, then point Cypress at that running application. Cypress explicitly advises: “Don’t try to start a web server from within Cypress scripts.” This keeps server lifecycle management outside the test code and makes failures easier to diagnose.
For example, suppose the application has a sign-in form at /login with accessible labels and a submit button. A spec can test what a user sees after entering credentials:
// cypress/e2e/login.cy.js
describe('sign-in', () => {
it('shows the account page after valid sign-in', () => {
cy.visit('/login')
cy.findByLabelText('Email').type('dev@example.com')
cy.findByLabelText('Password').type('correct-horse-battery-staple')
cy.findByRole('button', { name: 'Sign in' }).click()
cy.url().should('include', '/account')
cy.findByRole('heading', { name: 'Your account' }).should('be.visible')
})
})
This example assumes the app provides accessible labels, a sign-in route, and an account heading. Use selectors tied to accessible roles and labels where practical: they describe how a person interacts with the page and are less coupled to internal markup than styling classes. Cypress’s core commands include cy.visit, cy.get, .click(), .type(), and retryable assertions such as .should(). If using Testing Library query commands like findByRole and findByLabelText, install and configure the corresponding Cypress Testing Library integration; otherwise use Cypress-native selectors, for example cy.get('[data-cy="email"]').
Configure a base URL in Cypress configuration so specs can use relative paths. For a JavaScript config, the shape is:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}'
}
})
Adjust the URL, spec pattern, and module syntax to match the application’s actual server and project configuration. Cypress can also test deployed applications, but its E2E guide describes local development as its primary, optimized workflow.
4. Mount and test a component in a real browser
Cypress Component Testing mounts a component “directly in a real browser — not a simulated DOM,” as the Cypress documentation puts it. This is useful for checking rendered behavior and appearance in a browser without setting up a complete application journey.
After selecting Component Testing and completing the framework-specific setup, a React example might look like this:
// cypress/component/SaveButton.cy.jsx
import SaveButton from '../../src/SaveButton'
describe('<SaveButton />', () => {
it('calls onSave when clicked', () => {
const onSave = cy.stub().as('onSave')
cy.mount(<SaveButton onSave={onSave} />)
cy.findByRole('button', { name: 'Save' }).click()
cy.get('@onSave').should('have.been.calledOnce')
})
})
This example assumes React component support and a configured cy.mount command. The exact mount setup varies by framework and bundler; follow Cypress’s current integration instructions rather than copying a React setup into Vue, Angular, or Svelte.
5. Build a reliable workflow
- Keep tests focused on observable behavior. Assert the page state, accessible content, URL, or visible response that matters to a user. Avoid coupling every test to private component state or incidental DOM structure.
- Control your test data. Use known application state and repeatable fixtures or test accounts. A test that depends on unpredictable shared data can fail for reasons unrelated to the behavior under test.
- Keep external dependencies deliberate. Cypress advises weighing the value of tests that interact with external sites against the disruption and flake those dependencies can introduce. Prefer testing your own application and control network responses when the external service itself is not the subject.
- Run the server outside Cypress. Start it in a developer terminal or CI job before launching tests. Ensure the configured base URL points at the server actually started.
- Debug with the browser and run artifacts. Cypress provides browser automation capabilities such as screenshots, video, network stubbing, and debugging. These are tools for investigation, not a guarantee that tests cannot be flaky.
- Use CI resources appropriate to the workload. Cypress recommends at least 2 CPUs and 4 GB RAM for a CI machine, and 8 GB or more for long runs or video recording. The vendor notes that abrupt exits, missing or frozen video frames, and increased runtime can indicate insufficient resources. Treat these as planning guidance, not a benchmark.
6. Capture screenshots without adding browser setup
Browser screenshots can help document a failure, capture a visual state, or create an artifact for a bug report. Cypress’s browser workflow is useful when the screenshot is part of an application test. If you instead need a clean screenshot of a public URL without setting up browser automation, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It accepts one GET request and returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for options and parameter details.
Or skip the browser setup
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
Replace YOUR_API_KEY with your key and change the target URL as needed. Cookie banners are accepted like a visitor would accept them, and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say which page verdict and billing status applied. An MCP server gives AI agents such as Claude, Cursor, and other MCP clients the tools take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for free ScreenshotNeo screenshots.
7. Troubleshoot common Cypress failures
| Symptom | Likely cause | What to do |
|---|---|---|
cy.visit() cannot reach the page |
The server is not running, the base URL or port is wrong, or startup has not completed. | Start the app in the surrounding workflow, confirm the URL in a browser, and match baseUrl and the CI server command. |
| Element not found or action times out | The selector does not match, content has not appeared, or the test assumes a state the app did not reach. | Inspect the rendered page and Cypress command log; prefer accessible queries or stable test attributes, and assert the preceding state before acting. |
| Works locally but fails in CI | Different browser versions, environment variables, test data, timing, or limited machine resources. | Align browser and environment configuration, seed predictable data, inspect screenshots/video where enabled, and check CI CPU and memory against Cypress’s recommendations. |
| Component test setup cannot compile or mount | The framework, version, or bundler combination is unsupported or configured differently from the guide. | Check the live component support matrix and use the matching framework-specific mount and bundler setup. |
| Firefox launch fails on an older Cypress version | Firefox 141+ support requires Cypress 14.1.0 or newer per the installation guide. | Upgrade Cypress or use a supported browser/version combination. |
| Electron-related warning or future breakage | Electron is deprecated as a Cypress test browser. | Configure an installed Chrome, Edge, or Firefox browser. |
| Tests fail intermittently around an external page or service | The test depends on a changing external system, network, or third-party state. | Test your own behavior with controlled data or stub the dependency when its live behavior is outside the test’s scope. |
| Run exits abruptly or video is incomplete | The CI machine may lack resources for the run or recording workload. | Review memory and CPU; Cypress recommends at least 2 CPUs and 4 GB RAM, with 8 GB+ for longer runs or video recording. |
8. Performance, reliability, and cost
Performance: Choose test scope to fit the feedback you need. Component tests focus on a component; E2E tests exercise a running application and a broader journey. The supplied Cypress sources do not establish a universal runtime advantage, test count, or coverage target, so measure your own suite rather than adopting a generic threshold.
Reliability: Keep application startup in the workflow, use repeatable data, and avoid unnecessary external-site dependencies. Cypress runs in a controlled browser environment with debugging and network tools, but that does not eliminate flake or guarantee reliability.
Cost: The locally installed Cypress App is free and open source. Cypress Cloud is optional and has a free tier plus paid plans for teams that need recorded CI results, analytics, debugging, or orchestration. Its current pricing and entitlements can change; check the official pricing page before budgeting. Do not assume premium Cloud capabilities are included in the free App.
Screenshot cost: ScreenshotNeo has a free plan with 1,000 shots per month and no card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; annual billing gives two months free, and every feature is on every plan. Only clean shots are billed; the response includes verdict and billing headers. Review ScreenshotNeo and its documentation for current usage and options.
9. Learn Cypress from official material
If you are learning Cypress over the next couple of weeks, the official Real World Testing with Cypress portal is a practical sequence. The research snapshot lists four courses, more than 25 lessons, and more than 30 examples, covering a first application, testing foundations, Cypress fundamentals, and advanced concepts. Course counts can change. Work through installation and a first test, then practice forms, custom commands, multiple pages, user journeys, debugging, test data, and the distinctions among test types.
10. FAQ
Is Cypress only for end-to-end testing?
No. Cypress supports both E2E testing and component testing, subject to the framework and bundler support for component tests.
Does component testing run in a simulated DOM?
Cypress mounts the component in a real browser. That lets you inspect browser-rendered behavior and appearance at component scope.
Should a Next.js page that uses server-side methods be a component test?
Cypress recommends E2E testing for full Next.js pages that rely on server-only methods, since those methods do not run in a component test.
Do I need Cypress Cloud to use Cypress?
No. The Cypress App is locally installed, free, and open source. Cloud is an optional service for team CI results and related workflows.
Can I use Cypress to screenshot a URL outside my app tests?
You can use browser automation for test-related captures. For a one-request website screenshot API or an MCP workflow for AI agents, see ScreenshotNeo’s documentation.


