Generate Tests
When to use
- After plan-tests has produced
test-plan.md - Once per scenario
- When running as part of
run-testing-sessionpipeline (Stage 4, per scenario)
Inputs
- Scenario name and section number (e.g., "1.1")
docs/playwright-spec-testing/test-plan.md— steps, assertions, file pathdocs/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.clickfor 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:
- Look for YAML snapshots, screenshots, and trace files whose filenames/timestamps align with this scenario (same slug or timestamp range from the exploration report).
- 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.
- 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 oneawait 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] --headedReport 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] PassingIf test fails, mark Generated but not Passing:
### Status
- [x] Planned
- [x] Explored
- [x] Synthesized
- [x] Generated
- [ ] PassingKey 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)