When you clone a Playwright test repository and get Cannot find module '@playwright/test', you forgot to run npm install: node_modules is never committed to source control because it can reach several hundred megabytes, and npm install regenerates it from package.json in seconds. The related error, Executable doesn't exist at /home/user/.cache/ms-playwright/chromium-XXX, means the browser binaries are stale and need npx playwright install. This guide covers what package.json, package-lock.json, and node_modules each control, the commands you'll run regularly, and the version prefix syntax that determines when npm updates a package automatically.

What npm Is

npm (Node Package Manager) is a tool that:

1. Keeps a registry of JavaScript packages (over 2 million of them)

2. Downloads packages from that registry into your project

3. Tracks which packages your project needs

When someone writes useful code (like the Playwright framework), they publish it as a package on npm. Anyone else can then install that package instead of writing the same code themselves.

Playwright, TypeScript, ESLint, Faker.js, dotenv — all of these are npm packages that power your test automation setup.

The package.json File

Every Node.js project has a package.json file. It's the project's descriptor — it says what the project is, what it needs, and how to run it.

A typical Playwright project's package.json looks like:

{
  "name": "my-playwright-tests",
  "version": "1.0.0",
  "scripts": {
    "test": "npx playwright test",
    "test:headed": "npx playwright test --headed",
    "test:ui": "npx playwright test --ui"
  },
  "devDependencies": {
    "@playwright/test": "^1.44.0",
    "typescript": "^5.4.5"
  }
}

Key sections:
  • name: Your project name
  • scripts: Commands you can run with npm run
  • devDependencies: Packages needed for development (testing tools, linters)
  • dependencies: Packages needed to run the app in production (not relevant for test-only projects)

dependencies vs. devDependencies

| | dependencies | devDependencies |

|-|---------------|------------------|

| When used | In production (running the app) | In development only (building, testing, linting) |

| Example | express, react, axios | playwright, typescript, eslint |

| Install flag | npm install package-name | npm install -D package-name |

For QA automation repositories, almost everything goes in devDependencies. You're building test tooling, not a production application.

The node_modules Folder

When you run npm install, npm:

1. Reads package.json

2. Downloads all listed packages from the npm registry

3. Puts them in node_modules/

4. Also installs all THEIR dependencies (and their dependencies...)

That's why node_modules can have thousands of files even for a project with 3 direct dependencies. Playwright, for example, pulls in dozens of packages it depends on internally.

You never touch files inside node_modules directly. They're managed by npm. You never commit node_modules to git. The folder can be hundreds of megabytes. Instead, you commit package.json and package-lock.json, and anyone cloning the repo runs npm install to regenerate it.

Check your .gitignore:

node_modules/

This line should be there. If it's not, add it.

package-lock.json

When npm installs packages, it also creates/updates package-lock.json. This file records the exact versions of every package installed (including transitive dependencies).

Why it matters: package.json might say "playwright": "^1.44.0" (meaning 1.44.0 or any compatible newer version). package-lock.json records the exact version that was actually installed. This ensures everyone on the team gets identical dependency versions. Do commit package-lock.json to git. Unlike node_modules, this file is small and deterministic.

The Essential npm Commands

# Install all dependencies listed in package.json
npm install

# Install a specific package and add to devDependencies
npm install -D @faker-js/faker

# Install a specific package and add to dependencies
npm install dotenv

# Remove a package
npm uninstall @faker-js/faker

# Update all packages to their latest compatible versions
npm update

# Check for packages with known security vulnerabilities
npm audit

# Fix security vulnerabilities automatically (where possible)
npm audit fix

# Run a script defined in package.json
npm run test
npm run test:headed

# List all installed packages
npm list --depth=0

# See the version of a specific package
npm list playwright

The npx Command

npx runs an npm package without installing it globally. You'll see it constantly with Playwright:

# Run playwright test runner (uses the local version in node_modules)
npx playwright test

# Install Playwright browsers
npx playwright install

# Open Playwright's UI mode
npx playwright test --ui

# Run codegen
npx playwright codegen https://lab.becomeqa.com

When you run npx playwright test, it finds Playwright inside your local node_modules/.bin/ folder and runs it. This ensures you're using the project's specific version of Playwright, not a globally installed one.

Setting Up a New Playwright Project From Scratch

# Create and enter a new directory
mkdir my-test-project && cd my-test-project

# Initialize npm project (creates package.json)
npm init -y

# Install Playwright
npm init playwright@latest

# That's it — Playwright installs itself and its dependencies

Or if you're adding Playwright to an existing project:

npm install -D @playwright/test
npx playwright install

Common Issues and Fixes

"Cannot find module" error

Error: Cannot find module '@playwright/test'

Fix: Run npm install. You likely cloned a repo and forgot to install dependencies.

Outdated Playwright browsers

Error: Executable doesn't exist at /home/user/.cache/ms-playwright/chromium-XXX

Fix: Run npx playwright install. Browser binaries need updating.

Security vulnerabilities

found 3 vulnerabilities (1 moderate, 2 high)

Fix: Run npm audit fix. Review what gets updated. For unfixable vulnerabilities, check if they're in dev-only dependencies (less risky for test code).

node_modules conflicts after git pull

If someone updated dependencies, your local node_modules may be stale:

rm -rf node_modules
npm install

This is the nuclear option but always works.

Why Versions Have ^ and ~

In package.json:

"@playwright/test": "^1.44.0"

| Symbol | Meaning | Example |

|--------|---------|---------|

| ^1.44.0 | Compatible with 1.44.0 (updates minor and patch) | Accepts 1.45.0, 1.50.0 but not 2.0.0 |

| ~1.44.0 | Approximately 1.44.0 (updates patch only) | Accepts 1.44.1, 1.44.9 but not 1.45.0 |

| 1.44.0 | Exactly 1.44.0 | No updates |

For test automation projects, ^ (caret) is the standard. It keeps you up to date with minor improvements while protecting against major breaking changes.

Practical Knowledge for QA Engineers

You need to know:
  • What npm install does and when to run it (always after cloning, after someone updates package.json)
  • What package.json contains and how to read it
  • The difference between dependencies and devDependencies
  • How npm run test works (it runs the test script from package.json)
  • Why node_modules is not committed to git
You don't need to know:
  • How to publish packages to npm
  • How the package registry works internally
  • Yarn, pnpm (alternative package managers) — they do the same thing, Playwright works with any of them

This is enough to set up projects, install dependencies, run tests, and debug the most common setup issues you'll encounter.

→ See also: Installing Playwright: Step-by-Step Setup Guide (2026) | JavaScript for QA Engineers: The Minimum You Need to Start Automating | TypeScript for QA: Why Static Types Make Your Tests Better