Playwright lets you automate real browsers with reliable auto-waiting. This tutorial walks from zero to a CI-ready smoke test in under an hour.
What you will build
- Playwright configured for a Next.js or React app
- One critical user journey test (sign-in or checkout)
- HTML report and trace-on-failure locally
- GitHub Actions job that runs on every pull request
Prerequisites
- An app running locally (default `http://localhost:3000`)
- npm or pnpm
- Git repository with GitHub (optional, for CI section)
Step-by-step
- Run `npm init playwright@latest` and choose TypeScript, tests folder `e2e`, and install browsers when prompted.
- Add `webServer` to `playwright.config.ts` so Playwright starts your dev server before tests.
- Create `e2e/smoke.spec.ts` with a test that visits `/`, checks the page title, and clicks a primary CTA link.
- Replace brittle CSS selectors with `getByRole`, `getByLabel`, and `getByText`.
- Run `npx playwright test --ui` to debug interactively, then `npx playwright test` headless.
- Enable `trace: "on-first-retry"` and `screenshot: "only-on-failure"` in config for easier debugging.
Sample smoke test
import { test, expect } from "@playwright/test";
test("home page loads and contact link works", async ({ page }) => {
await page.goto("/");
await expect(page).toHaveTitle(/Kabim/i);
await page.getByRole("link", { name: /contact/i }).click();
await expect(page).toHaveURL(/\/contact/);
});webServer config
export default defineConfig({
webServer: {
command: "npm run dev",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
},
use: { baseURL: "http://localhost:3000" },
});Run in GitHub Actions
- Add a workflow file under `.github/workflows/e2e.yml`.
- Install dependencies, install Playwright browsers with `--with-deps`, run `npx playwright test`.
- Upload the `playwright-report` artifact when the job fails.
Tips
- Keep the first suite under 10 tests, speed builds trust
- One test user per environment; reset state in `beforeEach` if needed
- Quarantine flaky tests with a ticket, do not disable the whole suite
You now have a foundation to expand coverage for auth, forms, and payments.


