One Issue → One PR with visual proof.
Flow: Select one issue → Write test (BEFORE screenshot) → Fix → Test passes (AFTER screenshot) → PR with screenshot comment.
Golden Rule: Study ≥2 existing PASSING tests before writing any new test. Wrong fixture/selector usage is #1 failure cause.
Choose an open issue to work on, or pick randomly:
# Option A: List and manually select
gh issue list --repo <owner/repo> --state open --json number,title,body
# Option B: Pick one randomly
gh issue list --repo <owner/repo> --state open --json number,title | \
jq -r '.[] | "\(.number): \(.title)"' | shuf -n 1
```bash
git worktree add .worktrees/fix/
cd .worktrees/fix/
```
```bash
export E2E_SCREENSHOT_DIR="$(pwd)/e2e-screenshots"
```
Read ≥2 passing E2E tests to understand:
withProject, withSession, gotoSession, sdk)waitSessionIdle, runTerminal, openSettings)apply_patch, terminal commands, SDK methods)import { test, expect } from "../fixtures"
import { createScreenshotReporter } from "../screenshot-reporter"
test("feature description", async ({ page, withProject }) => {
const screenshot = createScreenshotReporter(page, "test-name")
await withProject(async (project) => {
// ... setup using project's fixture patterns ...
await screenshot.captureBefore("initial-state")
// ... assertions ...
})
})
Playwright TS transform gotcha — rejects inline object params:
// WRONG: fs.mkdirSync(dir, { recursive: true })
// RIGHT:
const opts = { recursive: true }
fs.mkdirSync(dir, opts)
Apply to ALL object literals: fs.mkdirSync, page.screenshot, page.waitForFunction, etc.
Write minimum code to pass. Do NOT modify test assertions.
page.waitForSelector or page.waitForFunction to confirm elements existpage.pause() to inspect live DOM| Symptom | Likely Cause | Fix |
|---|---|---|
| --- | --- | --- |
| Timeout on selector | Wrong data attribute or shadow DOM | Check DOM with page.pause(), try ARIA roles |
waitMark never resolves | Seed function missing expected content | Match seed format exactly from passing tests |
| Button not visible | Missing hover/expand step | Hover parent row, expand section first |
| Review panel empty | Wrong changes mode (git vs session) | Switch mode before asserting |
| Stale element reference | Race condition with async updates | Add waitSessionIdle after mutations |
await expect(fixedElement).toBeVisible()
await screenshot.captureAfter("feature-working")
Hard gate — ALL three must be true before PR:
BEFORE-*.png existsAFTER-*.png exists# Stage, commit, push
git add -A
git commit -m "fix: <issue-description> (closes #<issue-number>)"
git push origin fix/<slug>
# Create PR referencing the issue
gh pr create \
--title "fix: <short-description>" \
--body "Closes #<issue-number>
## Summary
<Brief description of the fix>
## Screenshots
| Before | After |
|--------|-------|
|  |  |
## Verification
- [x] E2E test passes
- [x] BEFORE screenshot captured
- [x] AFTER screenshot captured" \
--repo <owner/repo>
# Push screenshots to branch for GitHub raw URLs
git add e2e-screenshots/
git commit -m "chore: add e2e screenshots"
git push origin fix/<slug>
gh pr comment has no --attach — push images to branch, use raw GitHub URLs.
For PRs without direct UI changes, find the closest UI-exercisable path:
| Change Type | E2E Strategy | Real Example |
|---|---|---|
| --- | --- | --- |
| Config utility | Open settings dialog | openSettings(page) → screenshot config panel |
| Python resolver | Run terminal command | runTerminal(page, {cmd: "python3 --version"}) → show output |
| Race condition | Trigger rapid operations | Create file externally → click refresh → verify |
| State management | Multi-session switching | Select file in session A → switch to B → back to A |
| Cache bypass | Force refresh | Add external file → click refresh button → verify |
| URL parsing | Check connection status | openStatusPopover(page) → verify connected |
| Focus management | Verify focus after action | Open file → check prompt still focused |
NEVER use page.setContent() — always test through the real application.
# Select an issue (manual or random)
gh issue list --repo owner/repo --state open --json number,title
# Create worktree
git worktree add .worktrees/fix/ISSUE -b fix/ISSUE
cd .worktrees/fix/ISSUE
# Set screenshot dir
export E2E_SCREENSHOT_DIR="$(pwd)/e2e-screenshots"
# Run E2E test
npm run test:e2e -- <test-file>
# Push and create PR
git push origin fix/ISSUE
gh pr create --title "fix: ..." --body "Closes #N" --repo owner/repo
E2E_SCREENSHOT_DIR, never to main repopage.setContent() — real app onlyscreenshot-reporter.ts must be copied to each worktree's e2e/ (not on fix branches)共 1 个版本