level 02 / first-test

Your First Playwright Test

Install Playwright, understand playwright.config.ts, and write a test that runs in Chromium, Firefox, and WebKit simultaneously.

practice site: SauceDemo

Installation

# In an existing Node.js project
npm init playwright@latest

# Scaffolds: playwright.config.ts, tests/example.spec.ts,
# tests-examples/, .github/workflows/playwright.yml
# Installs: @playwright/test + browser binaries
# Install browsers separately (if already have @playwright/test)
npx playwright install

# Install specific browser
npx playwright install chromium
npx playwright test
Run all tests
npx playwright test --headed
Run with visible browser
npx playwright test --ui
Open Playwright UI mode (interactive debugger)
npx playwright test login.spec.ts
Run one file
npx playwright test --grep "login"
Run tests matching a pattern
npx playwright show-report
Open last HTML report
npx playwright codegen https://saucedemo.com
Record interactions as test code

The anatomy of a Playwright test

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

test('page title matches', async ({ page }) => {
  // Arrange: navigate to the page
  await page.goto('https://www.saucedemo.com');

  // Act: (none — reading state only)

  // Assert: check the title
  await expect(page).toHaveTitle('Swag Labs');
});
  • test() — registers a test case. The callback receives a fixture object.
  • { page } — the page fixture is a Playwright Page instance, auto-created per test.
  • async/await — every browser interaction is asynchronous.
  • expect() — wraps a locator or page value with auto-retry assertions.

playwright.config.ts

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

export default defineConfig({
  // Directory where test files live
  testDir: './tests',

  // Run tests in parallel (each test gets its own browser context)
  fullyParallel: true,

  // Fail the build on CI if test.only is left in source
  forbidOnly: !!process.env.CI,

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

  // Reporter: 'html' generates a browsable report
  reporter: 'html',

  // Shared settings for all projects
  use: {
    baseURL: 'https://www.saucedemo.com',
    trace: 'on-first-retry',  // record trace on first retry
  },

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

Your first real test

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

test.describe('SauceDemo login', () => {
  test('standard user can log in', async ({ page }) => {
    await page.goto('/');

    await page.getByPlaceholder('Username').fill('standard_user');
    await page.getByPlaceholder('Password').fill('secret_sauce');
    await page.getByRole('button', { name: 'Login' }).click();

    await expect(page.getByText('Products')).toBeVisible();
    await expect(page).toHaveURL(/inventory/);
  });

  test('locked out user sees error', async ({ page }) => {
    await page.goto('/');

    await page.getByPlaceholder('Username').fill('locked_out_user');
    await page.getByPlaceholder('Password').fill('secret_sauce');
    await page.getByRole('button', { name: 'Login' }).click();

    await expect(page.getByText('Sorry, this user has been locked out')).toBeVisible();
  });
});
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  reporter: 'html',
  use: {
    baseURL: 'https://www.saucedemo.com',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
  ],
});
Key insight: Use baseURL in playwright.config.ts so every page.goto('/') resolves to the right environment. Switch environments by changing one config value, not every test.

Running and debugging

# Run with UI mode (shows timeline, trace, DOM snapshot)
npx playwright test --ui

# Run in debug mode (step through test line by line)
npx playwright test --debug login.spec.ts

# Show the HTML report from the last run
npx playwright show-report

Interview questions