Skip to content

First Story (Playwright)

Create a spec file (e.g. src/login.story.spec.ts):

import { expect, test } from '@playwright/test';
import { story } from 'executable-stories-playwright';
test.describe('Login', () => {
test('user logs in successfully', async ({ page }, testInfo) => {
story.init(testInfo);
story.given('the user is on the login page');
await page.goto('/login');
story.when('the user submits valid credentials');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('secret');
await page.getByRole('button', { name: 'Sign in' }).click();
story.then('the user sees the dashboard');
await expect(page).toHaveURL(/dashboard/);
});
});

Use story.init(testInfo) at the start of the test (pass testInfo from the test callback), then story.given, story.when, story.then to mark steps. If you want step callbacks to receive fixtures, initialize with story.init({ page }, testInfo) instead.

Terminal window
pnpm playwright test

The reporter writes to your configured formats and paths. For Markdown output (for example docs/user-stories.md), the story above looks like:

### User logs in successfully
- **Given** the user is on the login page
- **When** the user submits valid credentials
- **Then** the user sees the dashboard

Run your reporter with --format html and your stories render into an interactive report:

Report Outputwhat this code generatesOpen live report ↗
The generated HTML report with Given/When/Then steps, a run summary, and search and status filters
Every framework adapter produces this same report. Click to open the live one.

Playwright story & doc API — steps, doc methods, and options.

Converting existing Playwright tests — adopt executable-stories without rewriting existing tests.

Recipes (Playwright) — more examples.