Skip to main content

How to Use Playwright with LiveDoc

Docs for Vitest SDK v0.3.3

LiveDoc provides a built-in Playwright integration that handles browser lifecycle and screenshot attachment. Write Gherkin scenarios that drive a real browser — screenshots become part of your living documentation automatically.

Prerequisites
  • A working LiveDoc Vitest setup (imports or globals)
  • A web application to test (running locally or in CI)

Install Playwright​

pnpm add -D playwright
npx playwright install chromium

LiveDoc's Playwright module is included in @swedevtools/livedoc-vitest — no additional package is needed.

Quick Start​

import { feature, scenario, given, when, then } from '@swedevtools/livedoc-vitest';
import { useBrowser, screenshot } from '@swedevtools/livedoc-vitest/playwright';

// Browser launches once, shared across all scenarios in this file
const { page, baseUrl } = useBrowser({
baseUrl: 'http://localhost:5174',
});

feature('User Login', () => {
scenario('Valid credentials', () => {
given("user navigates to '/login'", async (ctx) => {
await page().goto(`${baseUrl}${ctx.step.values[0]}`);
await screenshot(page(), ctx);
});

when("submitting username 'admin' and password 'secret'", async (ctx) => {
await page().fill('[name=username]', ctx.step.values[0]);
await page().fill('[name=password]', ctx.step.values[1]);
await page().click('button[type=submit]');
});

then("the dashboard is displayed", async (ctx) => {
await page().waitForURL('**/dashboard');
await screenshot(page(), ctx);
});
});
});

That's it — two imports, one useBrowser() call, and screenshot() wherever you want visual documentation.

API Overview​

useBrowser(options?)​

Call at module scope (outside feature()) to set up browser lifecycle. Returns getters for page, context, and browser.

const { page, context, browser, baseUrl } = useBrowser({
baseUrl: 'http://localhost:3000', // default
browser: 'chromium', // or 'firefox', 'webkit'
launch: { headless: true }, // passed to playwright browser.launch()
context: { viewport: { width: 1280, height: 720 } }, // passed to browser.newContext()
});
OptionTypeDefaultDescription
baseUrlstring'http://localhost:3000'Base URL for navigation
browser'chromium' | 'firefox' | 'webkit''chromium'Browser engine
launchRecord<string, unknown>{ headless: true }Playwright LaunchOptions
contextRecord<string, unknown>{}Playwright BrowserContextOptions
caution

Call page() inside steps, not at module scope. The page doesn't exist until beforeAll runs.

// ✅ Correct — inside a step
given("I open the app", async () => { await page().goto(baseUrl); });

// ❌ Wrong — at module scope (page is not initialized yet)
const p = page(); // throws!

screenshot(page, ctx, options?)​

Captures a screenshot and attaches it to the current step as a PNG. Auto-generates a name from the step title if none is provided.

// Auto-named from step title
await screenshot(page(), ctx);

// Custom name
await screenshot(page(), ctx, { name: 'checkout-confirmation' });

// Viewport only (not full page)
await screenshot(page(), ctx, { fullPage: false });
OptionTypeDefaultDescription
namestringAuto-generated from step titleScreenshot label
fullPagebooleantrueCapture entire scrollable area

Screenshots appear as attachments in the LiveDoc Viewer and static HTML reports.

Headed Mode for Local Development​

Run with a visible browser window during development:

const { page, baseUrl } = useBrowser({
baseUrl: 'http://localhost:5174',
launch: {
headless: process.env.CI === 'true',
slowMo: process.env.CI ? 0 : 250, // slow down for visual debugging
},
});

Starting Your Dev Server​

LiveDoc doesn't manage your dev server — use Vitest's globalSetup for that:

// globalSetup.ts
import { type GlobalSetupContext } from 'vitest/node';

export default async function setup({ provide }: GlobalSetupContext) {
// Start your dev server however your framework requires
const server = await startMyDevServer({ port: 5174 });

return async () => {
await server.close();
};
}
// vitest.config.ts
export default defineConfig({
test: {
globalSetup: './globalSetup.ts',
},
});

CI Configuration​

Playwright tests in CI need two things the local environment already has: browser binaries and a running application to test against.

Step 1 — Install Browsers​

- name: Install Playwright browsers
run: npx playwright install chromium --with-deps

The --with-deps flag installs system-level libraries (fonts, codecs) that headless Chromium needs on Linux runners. Only install the browsers you actually test against — chromium alone is usually sufficient.

Step 2 — Start Your Application​

Playwright tests navigate to a running web app. Start it in the background before running tests:

- name: Start application
run: |
npm run start &
# Wait until the server responds (up to 30 seconds)
timeout 30 bash -c 'until curl -sf http://localhost:3000 > /dev/null 2>&1; do sleep 1; done'
echo "Application is ready"
Don't forget the wait

Without the health-check loop, tests may start before the server is ready — leading to flaky connection-refused failures.

Step 3 — Run Tests​

- name: Run tests (including Playwright)
run: npx vitest run --config vitest.config.ci.ts

Complete GitHub Actions Example​

steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22

- run: npm ci

- name: Build
run: npm run build

- name: Install Playwright browsers
run: npx playwright install chromium --with-deps

- name: Start application
run: |
npm run start &
timeout 30 bash -c 'until curl -sf http://localhost:3000 > /dev/null 2>&1; do sleep 1; done'

- name: Run tests
run: npx vitest run --config vitest.config.ci.ts
Headed vs headless

Use the CI environment variable to toggle headed mode:

const { page } = useBrowser({
launch: { headless: process.env.CI === 'true' },
});

GitHub Actions sets CI=true automatically, so tests run headless in CI and can optionally run headed locally for visual debugging.

Troubleshooting​

ProblemCauseSolution
page is not initializedpage() called before beforeAll runsMove page() calls inside step functions
playwright module not foundPeer dependency missingRun pnpm add -D playwright
Browser fails to launch in CIMissing system dependenciesUse npx playwright install --with-deps chromium
Screenshots are blankPage hasn't finished loadingAdd await page().waitForLoadState('networkidle') before screenshot