ScreenshotNeo

BlogHow-to

How to Write and Run Cypress Tests

Install Cypress, write independent JavaScript tests, run them interactively or from the CLI, and avoid common CI setup failures.

By the ScreenshotNeo team4 October 20268 min read

To write and run Cypress tests, install Cypress as a development dependency, use its Launchpad to configure end-to-end (E2E) or component testing, write focused tests that can run independently, and use cypress open while developing. Run cypress run to execute tests to completion in a terminal or CI. These modes are complementary: choose the test type that matches what you want to verify, and you can use both in the same project.

1. Install Cypress

From your project root, use the package manager the project already uses. For npm:

npm install cypress --save-dev

Equivalent commands are:

yarn add cypress --dev
pnpm add --save-dev cypress
bun add --dev cypress

Cypress normally downloads its matching binary during package installation. If your environment blocks lifecycle scripts or you intentionally deferred the binary download, install it separately with npx cypress install. See the official installation guide.

2. Configure the project on first launch

Start the interactive setup from the project root:

npx cypress open

Use yarn cypress open, pnpm cypress open, or bunx cypress open if that fits your package manager. On first launch, Cypress’s Launchpad helps you select E2E or component testing, choose a browser, and create or review the initial configuration and folder structure. Selecting one type does not prevent adding the other later.

The generated project commonly includes cypress.config.js, a fixtures directory, and a support file such as cypress/support/e2e.js or cypress/support/component.js. The support file loads before the selected spec, so reserve it for setup and hooks that genuinely apply across that test type. Keep spec-specific imports and setup in the relevant spec. Cypress’s defaults are conventions; the directory structure and spec matching can be configured.

For a repeatable team command, add a descriptive script to package.json:

{
  "scripts": {
    "cy:open": "cypress open",
    "cy:run": "cypress run"
  }
}

Then run npm run cy:open or npm run cy:run. Avoid naming a script cypress, which can conflict with Yarn command resolution.

3. Choose E2E or component testing

Test type Use it for Typical focus
End-to-end (E2E) Checking an application through its browser-facing routes and workflows Visiting a page, interacting with controls, and asserting the resulting user-visible state
Component testing (CT) Checking a component in isolation within a browser Rendering a component and verifying its behavior for given props or interactions

Choose the mode based on the behavior under test. E2E tests cover flows through the app; component tests focus on a smaller UI unit. A project can use both, with the corresponding configuration and support files.

4. Write a focused, independent spec

A Cypress spec is a JavaScript test file. For example, an E2E spec might contain:

describe('home page', () => {
  it('shows the main heading', () => {
    cy.visit('/')
    cy.get('h1').should('be.visible')
  })
})

This is a generic pattern: it assumes the application is running, the configured base URL points to it, and the page has an h1. Adapt the route and assertion to your app. Prefer selectors that remain stable as styling changes, and assert outcomes a user can observe.

Keep tests independent. A test should establish the state it needs rather than relying on an earlier test to leave the browser or server in a particular state. Cypress warns that tests coupled through shared state can fail when run alone, reordered, or skipped. Independence makes failures easier to reproduce and lets you target one spec while debugging.

Set the application URL

For E2E tests, configure the app’s base URL in the project’s Cypress configuration so cy.visit('/') resolves to the application. For example, a JavaScript configuration can include:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000'
  }
})

Use the actual local address and the configuration format already present in your project. In component testing, use the component-testing configuration generated for your framework instead of treating a component spec as an E2E page visit.

Use fixtures and network stubs deliberately

For static test data checked into the project, put it in a fixture and stub the relevant request:

cy.intercept('GET', '/api/users', { fixture: 'users.json' })

Fixtures are useful when a test needs a known response. Cypress caches fixture data, so use cy.readFile() for files that change or are created by the application. For larger files or work that must run in Node.js, use cy.task(). If a spec creates cases from data, import that data statically so the test cases exist when Cypress loads the spec.

5. Run tests interactively while developing

Use:

npx cypress open

The interactive workflow opens the selected browser, shows the specs, and runs the selected spec. Cypress watches for edits and reruns the active spec, while the Command Log and test-step history help you inspect the run. This is the usual editing loop: change a test or app behavior, review the browser result, and refine the assertion.

6. Run tests from the terminal

Run the suite to completion with:

npx cypress run

cypress run is headless by default. To run one spec, select it explicitly:

npx cypress run --spec "cypress/e2e/home.cy.js"

To select a browser or configuration file:

npx cypress run --browser chrome
npx cypress run --config-file cypress.config.js

Use a browser installed and supported in your environment. Check the project’s configured specPattern if a path passed to --spec is not discovered: the requested file must also match that pattern. See the Cypress CLI reference for available options.

7. Run Cypress in CI

A CI job needs to install the project dependencies and Cypress, start the app, wait until the app is reachable, and then run Cypress. Starting the server and Cypress together without checking readiness creates a race: Cypress may try to visit the app before the server has finished booting. The Cypress CI guide recommends a readiness check, such as a wait utility or the Cypress GitHub Action’s documented start and wait-on options.

A minimal outline for a CI shell step is:

npm ci
npm run build
npm start &
# Wait for the application URL to respond using your CI provider's readiness utility.
npx cypress run

The comment is intentional: configure the readiness utility provided by your environment to wait for the actual app URL before the final command. Do not replace it with an arbitrary fixed sleep; a sleep can be too short on a slow run and waste time on a fast one. Follow your CI provider’s process management guidance for starting and stopping the server.

Keep credentials and other secrets in your CI provider’s secret storage. Avoid passing secrets as command-line arguments, where they may be exposed in logs. Make the CI browser, environment variables, and app URL consistent with the conditions the suite is meant to cover.

8. Troubleshoot common problems

Symptom Likely cause Fix
cy.visit() cannot reach the app in CI Cypress started before the server was ready, or the configured URL is wrong. Check baseUrl and the app address, then make CI wait for that URL to respond before running Cypress.
A test passes in the full suite but fails alone, or vice versa It relies on state left by another test or has hidden shared setup. Make setup explicit and ensure the test can run by itself and in a different order.
No tests run for the selected spec The path is wrong or the file does not match specPattern. Check the path and configured pattern; use a matching spec path with --spec.
Cypress is installed but its binary is missing Lifecycle scripts or binary download were blocked or deferred. Run npx cypress install in the same environment and confirm the install step can download the binary.
A fixture does not reflect the latest generated file Fixtures are cached for test use. Use cy.readFile() for changing files, or cy.task() for Node-side or large-file work.
A secret appears in CI output It was passed as a CLI argument or printed by a command. Move it to CI secret storage and avoid echoing it or including it in command arguments.
The interactive runner cannot find the expected spec type The Launchpad setup or project configuration does not match the test you are trying to run. Open Cypress, select the intended testing type, and review the corresponding configuration, support file, and spec location.

9. Reliability, runtime, and cost considerations

  • Reliability: Independent tests, explicit setup, and a CI readiness check reduce failures caused by hidden state or startup races.
  • Runtime: Run one spec with --spec while iterating on a focused change. Use interactive mode for feedback during authoring and the completion-oriented CLI run for repeatable suite execution.
  • Test data: Stub known responses with fixtures when that makes the scenario deterministic; use file-reading or task mechanisms when data changes or requires Node.js.
  • CI security: Store secrets in the provider’s secret facility instead of command-line arguments or logs.
  • Cost: Cypress is installed as a project dependency. This workflow alone does not establish a price for any hosted or team services; check the relevant current product terms if your setup uses services beyond the local CLI.

Or skip the browser setup

If you need a website image for a report, preview, or agent workflow, ScreenshotNeo provides a website screenshot API and MCP server. It does not run Cypress tests or validate application behavior; it captures a page as an image or PDF.

One GET request returns a screenshot. See the ScreenshotNeo API documentation for the request options.

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}`);
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers identify the page verdict and billing status.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.

FAQ

Can one project use both E2E and component tests?

Yes. They are separate testing modes for different targets, and selecting one during first-run setup does not rule out configuring the other.

Should I use cypress open or cypress run?

Use open for interactive authoring and debugging. Use run to execute tests to completion, including in CI.

Why can a test behave differently when run by itself?

It may depend on state created by another test. Each test should set up the conditions it needs so it can run independently.

Where should shared Cypress setup go?

Put setup that genuinely applies to all specs of a test type in its support file. Keep setup specific to one spec close to that spec.

Official Cypress references