Installing Cypress with TypeScript

8 min read

You know what Cypress is. Time to install it. This lesson takes you from an empty folder to a fully scaffolded TypeScript Cypress project — including a working cypress.config.ts, a typed tsconfig.json, and a real test file you can run before the lesson ends. Every command in this lesson is meant to be typed into your terminal as you read.

Prerequisites

Before you start, you need:

  • Node.js v18 or later. Run node --version to confirm. If you're on Node 16, upgrade — Cypress 13+ won't install cleanly on older runtimes.
  • A code editor. VS Code is what every example in this course assumes. The Cypress team publishes first-party TypeScript types, and VS Code's hover-tooltips on cy.* commands are one of the things you'll come to rely on.
  • Working knowledge of JavaScript and TypeScript as covered in JavaScript for QA and TypeScript for QA. We won't re-explain const, generics, or interfaces here.

If node --version prints something v18 or higher and you can open a terminal in VS Code, you're ready.

Creating the project

We'll build a real e-commerce test project across this course — the same scaffold you'd use at work. Start clean:

mkdir cypress-ecommerce-tests
cd cypress-ecommerce-tests
npm init -y
npm install cypress typescript --save-dev

Three things happened:

  1. npm init -y created package.json with default values.
  2. npm install cypress typescript --save-dev downloaded both packages into node_modules and added them to devDependencies. Cypress is around 200 MB on disk because it bundles its own Electron browser — that's normal, not a mistake.
  3. The --save-dev flag pinned both as development dependencies, since they're tools you use to test the app rather than ship in production.

You don't need to install @types/cypress separately. Cypress ships its own TypeScript declarations inside the cypress package itself. Same for the test runner Mocha — its globals are typed and pulled in automatically.

First launch — the scaffolder

The first time you run cypress open, the Cypress desktop app walks you through scaffolding. Run it now:

npx cypress open

A window appears. Click E2E Testing. Cypress detects this is a fresh project and offers to create a starter folder structure. Click Continue. It then asks you to pick a browser — choose Chrome if you have it (Edge and Firefox work too; bundled Electron is a fine fallback).

After scaffolding completes, your project tree looks like this:

cypress-ecommerce-tests/
├── cypress/
│   ├── e2e/                 ← spec files (.cy.ts) live here
│   ├── fixtures/            ← test data (JSON, CSV, etc.)
│   ├── support/
│   │   ├── commands.ts      ← custom commands
│   │   └── e2e.ts           ← runs before every spec
│   └── downloads/           ← files saved during tests
├── cypress.config.ts        ← top-level Cypress config
├── tsconfig.json            ← TypeScript config (auto-created)
├── package.json
└── package-lock.json

Each folder has a job. cypress/e2e/ is where you put your tests. cypress/fixtures/ is where you put deterministic test data — JSON files, CSV uploads, anything a test needs to read. cypress/support/commands.ts is where you'll define custom commands like cy.login(...) later in chapter 5. cypress/support/e2e.ts is the global setup file that runs before every spec — you'll wire up cross-cutting plugins like cypress-axe here in chapter 7.

Reading cypress.config.ts

Open cypress.config.ts at the project root:

import { defineConfig } from "cypress";
 
export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  },
});

defineConfig is a typed wrapper that gives you autocomplete on every config option — hover over it in VS Code and you'll see the full schema. Three options you'll change immediately:

import { defineConfig } from "cypress";
 
export default defineConfig({
  e2e: {
    baseUrl: "http://localhost:3000",
    viewportWidth: 1280,
    viewportHeight: 720,
    setupNodeEvents(on, config) {
      // hooks for fixtures, plugins, env vars
    },
  },
});
  • baseUrl lets you call cy.visit("/products") instead of the full URL. Without it, cy.visit("/") errors out.
  • viewportWidth and viewportHeight control the browser window size during tests. Set them once here and every test inherits them.

Save the file. The runner picks up changes live; no restart needed.

The TypeScript config

Cypress auto-generates cypress/tsconfig.json (note: it's nested under cypress/, not the root):

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM"],
    "types": ["cypress", "node"],
    "moduleResolution": "node"
  },
  "include": ["**/*.ts"]
}

The line that matters most is "types": ["cypress"]. That's what wires cy, Cypress, describe, and it into the global scope for every file in cypress/. Without it, the editor underlines the entire framework as undeclared. If you ever see "Cannot find name 'cy'," check this line first.

Verify with a one-line test

Drop this into cypress/e2e/sanity.cy.ts:

describe("Sanity check", () => {
  it("Cypress is wired up correctly", () => {
    cy.wrap("hello cypress").should("equal", "hello cypress");
  });
});

Save the file. The Cypress runner shows it in the spec list. Click it. The browser opens, the test runs, and you see a green check next to "Cypress is wired up correctly". cy.wrap doesn't need a real app — it just wraps a value in a Cypress chainable so we can run an assertion against it. If this passes, your installation is healthy.

Add npm scripts

Stop typing npx cypress every time. In package.json:

{
  "scripts": {
    "cy:open": "cypress open",
    "cy:run": "cypress run",
    "cy:run:chrome": "cypress run --browser chrome"
  }
}

Now npm run cy:open launches the runner and npm run cy:run does a headless CI-style run. Every Cypress project in this course uses these three scripts as the standard surface — get into the habit now.

The full installation flow

Step 1 of 5

npm init

mkdir + cd + npm init -y to create package.json. The folder name (e.g. cypress-ecommerce-tests) is yours; everything else lives below it.

While the runner is open, pull up VS Code and install these:

  • Cypress Snippets (andrew-codes.cypress-snippets) — autocomplete for common Cypress patterns.
  • ESLint (dbaeumer.vscode-eslint) — catches typos and dead code in your specs.
  • Prettier (esbenp.prettier-vscode) — auto-formats .ts and .cy.ts files on save.

Add eslint-plugin-cypress to the project if you want lint rules tuned for Cypress: npm install eslint eslint-plugin-cypress --save-dev. The full Cypress reference is on the Cypress tools page and the commands cheat sheet.

⚠️ Common mistakes

  • Editing the root tsconfig.json instead of cypress/tsconfig.json. Cypress test files live under cypress/ and read the nested config — that's the file that needs "types": ["cypress"]. Adding the same line at the project root has no effect on test files. The symptom is "Cannot find name 'cy'" everywhere even though you swear you fixed it.
  • Skipping npx cypress open and trying to scaffold by hand. The first launch generates not just folders but also tuned tsconfig.json, support stubs, and example specs you can delete. Hand-rolling means you'll forget something subtle (like the support file being loaded before every spec) and spend an hour debugging it.
  • Installing @types/cypress from npm. It used to exist; it doesn't apply to modern Cypress. The official types are bundled inside the cypress package. Installing the deprecated @types package can shadow the real ones and break autocomplete in confusing ways. If you have it in package.json, remove it.

🎯 Practice task

Build the project you'll use for the rest of this course. 20-30 minutes.

  1. Create a folder cypress-ecommerce-tests/ and run the four install commands from the lesson. Confirm node_modules/cypress exists and package.json lists cypress and typescript under devDependencies.

  2. Run npx cypress open and let it scaffold. Inspect the generated tree and confirm the structure matches the diagram in the lesson.

  3. Open cypress.config.ts and add baseUrl: "https://example.cypress.io" (a public Cypress demo site). Save.

  4. Create cypress/e2e/sanity.cy.ts with the one-line test from the lesson. Run it from the runner — it should pass.

  5. Now create a second spec, cypress/e2e/visit.cy.ts:

    describe("Demo site", () => {
      it("loads the Cypress example homepage", () => {
        cy.visit("/");
        cy.get("h1").should("be.visible");
      });
    });

    Click it in the runner. The Cypress example page loads, the test passes, and you've made your first real navigation.

  6. Add the three npm scripts (cy:open, cy:run, cy:run:chrome) to package.json. Run npm run cy:run from the terminal — you should see both specs execute headlessly with a green summary.

  7. Stretch: in cypress/tsconfig.json, deliberately remove "cypress" from the types array. Save. Open any spec — the cy global is now red squiggles in VS Code. Put "cypress" back. Watch the squiggles disappear. You've just felt exactly what the type-resolution wiring buys you.

The next lesson takes this scaffolded project and writes a multi-test spec against a real e-commerce flow — products, search, filters — with assertions that use should, each, and beforeEach.

// tip to track lessons you complete and pick up where you left off across devices.