🔥 0
0
Lesson 2 of 10 20 min +150 XP

Setup & First Test

Let's get Playwright running and write your first test against a real e-commerce scenario.

Prerequisites

You need Node.js 18+ installed. Check your version:

node --version
# Should show v18.x.x or higher

Installation

Option 1: New Project (Recommended for Learning)

# Create a new directory and initialize
mkdir ecommerce-tests
cd ecommerce-tests
npm init -y

# Install Playwright
npm init playwright@latest

The init wizard asks a few questions:

✔ Do you want to use TypeScript or JavaScript? › TypeScript
✔ Where to put your end-to-end tests? › tests
✔ Add a GitHub Actions workflow? › true
✔ Install Playwright browsers? › true

Option 2: Existing Project

# Install the package
npm install -D @playwright/test

# Install browsers (Chromium, Firefox, WebKit)
npx playwright install

What Gets Installed?

When you run npx playwright install, Playwright downloads:

BrowserEngineSize
ChromiumChrome/Edge~280 MB
FirefoxMozilla~250 MB
WebKitSafari~180 MB

These are not your system browsers. Playwright installs specific versions it's tested against.

Project Structure

After initialization, your project looks like this:

ecommerce-tests/
├── tests/
│   └── example.spec.ts    # Example test file
├── tests-examples/
│   └── demo-todo-app.spec.ts
├── playwright.config.ts   # Configuration
├── package.json
└── package-lock.json

The Config File

playwright.config.ts controls everything:
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // Test directory
  testDir: './tests',

  // Run tests in parallel
  fullyParallel: true,

  // Fail CI if test.only is left in code
  forbidOnly: !!process.env.CI,

  // Retry failed tests in CI
  retries: process.env.CI ? 2 : 0,

  // Parallel workers
  workers: process.env.CI ? 1 : undefined,

  // Reporter
  reporter: 'html',

  // Shared settings for all tests
  use: {
    // Base URL for relative navigation
    baseURL: 'https://shop.example.com',

    // Collect trace on first retry
    trace: 'on-first-retry',

    // Screenshot on failure
    screenshot: 'only-on-failure',
  },

  // Browser configurations
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

Your First E-Commerce Test

Delete the example files and create tests/product-page.spec.ts:

import { test, expect } from '@playwright/test';

test.describe('Product Page', () => {
  test('displays product details correctly', async ({ page }) => {
    // Navigate to a product page
    await page.goto('https://demo.playwright.dev/svgomg');
    // Note: Replace with your actual e-commerce URL

    // Verify the page loaded
    await expect(page).toHaveTitle(/SVGOMG/);
  });
});

Let's use a real e-commerce demo site. Create tests/ecommerce.spec.ts:

import { test, expect } from '@playwright/test';

// Using Sauce Demo - a public e-commerce test site
const BASE_URL = 'https://www.saucedemo.com';

test.describe('E-Commerce Product Flow', () => {
  test.beforeEach(async ({ page }) => {
    // Login before each test
    await page.goto(BASE_URL);
    await page.getByPlaceholder('Username').fill('standard_user');
    await page.getByPlaceholder('Password').fill('secret_sauce');
    await page.getByRole('button', { name: 'Login' }).click();

    // Verify we're on the products page
    await expect(page.getByText('Products')).toBeVisible();
  });

  test('can view product details', async ({ page }) => {
    // Click on a product
    await page.getByText('Sauce Labs Backpack').click();

    // Verify product page elements
    await expect(page.getByText('Sauce Labs Backpack')).toBeVisible();
    await expect(page.getByText('$29.99')).toBeVisible();
    await expect(page.getByRole('button', { name: 'Add to cart' })).toBeVisible();
  });

  test('can add product to cart', async ({ page }) => {
    // Add first product to cart
    await page.getByRole('button', { name: 'Add to cart' }).first().click();

    // Verify cart badge shows 1
    await expect(page.locator('.shopping_cart_badge')).toHaveText('1');
  });

  test('can complete checkout flow', async ({ page }) => {
    // Add product to cart
    await page.getByRole('button', { name: 'Add to cart' }).first().click();

    // Go to cart
    await page.locator('.shopping_cart_link').click();
    await expect(page.getByText('Your Cart')).toBeVisible();

    // Proceed to checkout
    await page.getByRole('button', { name: 'Checkout' }).click();

    // Fill checkout form
    await page.getByPlaceholder('First Name').fill('John');
    await page.getByPlaceholder('Last Name').fill('Doe');
    await page.getByPlaceholder('Zip/Postal Code').fill('12345');
    await page.getByRole('button', { name: 'Continue' }).click();

    // Verify checkout overview
    await expect(page.getByText('Checkout: Overview')).toBeVisible();

    // Complete purchase
    await page.getByRole('button', { name: 'Finish' }).click();

    // Verify success
    await expect(page.getByText('Thank you for your order!')).toBeVisible();
  });
});

Running Tests

Run All Tests

npx playwright test

Output:

Running 3 tests using 3 workers

  ✓ [chromium] tests/ecommerce.spec.ts:15:7 › can view product details (2.3s)
  ✓ [chromium] tests/ecommerce.spec.ts:24:7 › can add product to cart (1.8s)
  ✓ [chromium] tests/ecommerce.spec.ts:31:7 › can complete checkout flow (3.1s)

  3 passed (4.2s)

Run Specific Test File

npx playwright test tests/ecommerce.spec.ts

Run Tests in Headed Mode (See the Browser)

npx playwright test --headed

Run in UI Mode (Interactive)

npx playwright test --ui

This opens a powerful visual interface where you can:

  • Watch tests run in real-time
  • See DOM snapshots at each step
  • Filter and re-run specific tests
  • Time-travel through test execution

Run Single Test by Name

npx playwright test -g "can add product to cart"

Run in Specific Browser

npx playwright test --project=firefox

Understanding Test Output

HTML Report

After tests run, open the HTML report:

npx playwright show-report

This shows:

  • Pass/fail status for each test
  • Test duration
  • Screenshots on failure
  • Traces (if enabled)

Console Output Explained

Running 3 tests using 3 workers
              ↑              ↑
         Total tests    Parallel processes

  ✓ [chromium] tests/ecommerce.spec.ts:15:7 › can view product details
    ↑           ↑                      ↑
  Browser    File path            Line number

Project Configuration for E-Commerce

Update playwright.config.ts for e-commerce testing:

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html'],
    ['list'],
  ],

  use: {
    // Your e-commerce site
    baseURL: process.env.BASE_URL || 'https://www.saucedemo.com',

    // Capture screenshot on failure
    screenshot: 'only-on-failure',

    // Record video on failure
    video: 'on-first-retry',

    // Capture trace for debugging
    trace: 'on-first-retry',

    // Reasonable timeouts for e-commerce
    actionTimeout: 15000,  // 15s for actions (add to cart, etc.)
    navigationTimeout: 30000,  // 30s for page loads
  },

  // Test timeout
  timeout: 60000,  // 60s per test (checkout flows can be slow)

  projects: [
    // Desktop browsers
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },

    // Mobile browsers (important for e-commerce!)
    {
      name: 'mobile-chrome',
      use: { ...devices['Pixel 5'] },
    },
    {
      name: 'mobile-safari',
      use: { ...devices['iPhone 13'] },
    },
  ],
});

Useful Scripts in package.json

Add these to your package.json:

{
  "scripts": {
    "test": "playwright test",
    "test:headed": "playwright test --headed",
    "test:ui": "playwright test --ui",
    "test:debug": "playwright test --debug",
    "test:chrome": "playwright test --project=chromium",
    "test:mobile": "playwright test --project=mobile-chrome --project=mobile-safari",
    "report": "playwright show-report"
  }
}

Now you can run:

npm test              # Run all tests
npm run test:headed   # Watch tests run
npm run test:ui       # Interactive UI mode
npm run test:mobile   # Mobile browser tests only

Troubleshooting

"Browser not found" Error

# Reinstall browsers
npx playwright install

"Timeout" Errors

Your site might be slow. Increase timeouts in config:

use: {
  actionTimeout: 30000,
  navigationTimeout: 60000,
}

Tests Pass Locally, Fail in CI

Usually a timing issue. Enable traces:

use: {
  trace: 'on',  // Always capture traces
}

Then download and view traces from CI artifacts.

Key Takeaways

  • Installation is simple: npm init playwright@latest handles everything
  • Browsers are managed: Playwright installs and updates them for you
  • Config is powerful: Control timeouts, browsers, reporters, and more
  • Multiple run modes: Headless, headed, UI mode, debug mode
  • E-commerce ready: Configure appropriate timeouts for payment flows
  • HTML reporter: Built-in beautiful test reports

Next Lesson

You've written tests, but those locators like .shopping_cart_badge are brittle. In the next lesson, we'll learn locator strategies that don't break when developers refactor.

Why Playwright in 2026