generate-tests

Installation
SKILL.md

Generate Tests

When to use

  • After plan-tests has produced test-plan.md
  • Once per scenario
  • When running as part of run-testing-session pipeline (Stage 4, per scenario)

Inputs

  • Scenario name and section number (e.g., "1.1")
  • docs/playwright-spec-testing/test-plan.md — steps, assertions, file path
  • docs/playwright-spec-testing/project-context.md — test conventions and reusable infrastructure

What it does

Write a Playwright test using ONLY selectors from the exploration report. No guessing. No invented selectors.

Phase 0: Check for reusable test infrastructure

Before writing any test code, read ## Reusable Test Infrastructure from docs/playwright-spec-testing/project-context.md. If the section is absent or contains only ### Notes — No reusable infrastructure detected, skip this phase and proceed directly to Phase 1 using raw page.* calls.

  • If a fixture handles auth or setup for this scenario, use it in the test function signature (e.g., async ({ authenticatedPage })) instead of manual login steps.
  • If a page object covers one or more steps, import it and call its methods instead of raw Playwright calls.
  • If an auth helper exists, call it instead of writing page.fill + page.click for login.
  • Only fall back to raw page.* calls when no abstraction covers the action.

Import paths must be derived from the actual file paths found in ## Reusable Test Infrastructure.

Phase 0.5: Load .playwright-cli artifact context

Before writing test code, check for .playwright-cli/ artifacts matching this scenario's slug and section number:

  1. Look for YAML snapshots, screenshots, and trace files whose filenames/timestamps align with this scenario (same slug or timestamp range from the exploration report).
  2. For each artifact found:
    • YAML snapshots — cross-check selectors in the plan against the snapshot's DOM. If the plan's selector differs from the snapshot, use the snapshot's selector and add a comment: // selector overridden from .playwright-cli snapshot.
    • Screenshots — add a reference comment above the relevant step: // screenshot: .playwright-cli/<filename>.png. Do NOT use screenshots to generate assertions — documentary only.
    • Trace files — if a trace shows a navigation event or network request accompanying a step, consider whether waitForURL or waitForResponse is more appropriate than a visibility assertion. Only apply if the trace strongly indicates it.
  3. If .playwright-cli/ is absent or no matching artifacts exist, skip this phase and proceed to Phase 1 unchanged.

Phase 1: Write the test file

Read the scenario's section in test-plan.md. This file already specifies every step and every expect: assertion — your job is mechanical translation to Playwright API calls. Do not infer, synthesize, or add anything not in the plan.

Follow conventions from project-context.md. Default to TypeScript if no convention.

Translate each step to a Playwright action. Translate each expect: line to an await expect(...) assertion. Use the selectors and URLs exactly as written in the plan.

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

test.describe('[Scenario Name]', () => {
  test('[scenario name as test title]', async ({ page }) => {
    // Step 1: <action from plan>
    await page.goto('[url from plan]');

    // Step 2: <action from plan>
    await page.getByLabel('Email').fill('user@example.com');
    await expect(page.getByText('Sign In')).toBeVisible(); // expect: from plan

    await page.getByRole('button', { name: 'Sign In' }).click();

    // Expected outcomes
    await expect(page).toHaveURL('/dashboard');
    await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
  });
});

Rules:

  • Use selectors as written in test-plan.md — do not paraphrase or invent
  • Every expect: line in the plan becomes one await expect(...) call
  • Steps with no expect: lines get no assertion
  • One test() per scenario
  • await before every Playwright action and assertion
  • NO page.waitForTimeout() — use built-in auto-waiting
  • If file exists, read it first and append (don't overwrite)
  • Before inserting a selector string into TypeScript, verify it contains no unescaped quotes or characters that would break out of a string literal. If a selector looks malformed, report BLOCKED instead of using it.

Phase 2: Run the test

Before running, verify TEST_FILE_PATH is a relative path within the project directory (no .. segments, no absolute paths, no shell metacharacters). If the path looks invalid, report BLOCKED.

./node_modules/.bin/playwright test [TEST_FILE_PATH] --headed

Report the result (PASS or FAIL with error output).

Phase 3: Update parsed-spec.md

If test passes:

### Status
- [x] Planned
- [x] Explored
- [x] Synthesized
- [x] Generated
- [x] Passing

If test fails, mark Generated but not Passing:

### Status
- [x] Planned
- [x] Explored
- [x] Synthesized
- [x] Generated
- [ ] Passing

Key Rules

  • NEVER use complex CSS selectors unless exploration explicitly captured one
  • NEVER add fake test data not in exploration report
  • NEVER add page.waitForTimeout()
  • Read existing test files before writing to avoid overwrites

Output

  • Test file at path from test-plan.md
  • Updated docs/playwright-spec-testing/parsed-spec.md

Report when done:

  • Status: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
  • Test file path
  • Test result: PASS or FAIL (include full error output if FAIL)
  • Selectors used (count)
Related skills
Installs
9
First Seen
Apr 7, 2026