mcp-subagents-opencode 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +602 -0
- package/build/config/timeouts.d.ts +9 -0
- package/build/config/timeouts.d.ts.map +1 -0
- package/build/config/timeouts.js +18 -0
- package/build/config/timeouts.js.map +1 -0
- package/build/helpers.d.ts +6 -0
- package/build/helpers.d.ts.map +1 -0
- package/build/helpers.js +47 -0
- package/build/helpers.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +245 -0
- package/build/index.js.map +1 -0
- package/build/models.d.ts +32 -0
- package/build/models.d.ts.map +1 -0
- package/build/models.js +58 -0
- package/build/models.js.map +1 -0
- package/build/server/register-notifications.d.ts +3 -0
- package/build/server/register-notifications.d.ts.map +1 -0
- package/build/server/register-notifications.js +77 -0
- package/build/server/register-notifications.js.map +1 -0
- package/build/server/register-resources.d.ts +3 -0
- package/build/server/register-resources.d.ts.map +1 -0
- package/build/server/register-resources.js +210 -0
- package/build/server/register-resources.js.map +1 -0
- package/build/server/register-retry-execution.d.ts +2 -0
- package/build/server/register-retry-execution.d.ts.map +1 -0
- package/build/server/register-retry-execution.js +28 -0
- package/build/server/register-retry-execution.js.map +1 -0
- package/build/server/register-tasks.d.ts +3 -0
- package/build/server/register-tasks.d.ts.map +1 -0
- package/build/server/register-tasks.js +52 -0
- package/build/server/register-tasks.js.map +1 -0
- package/build/server/register-tools.d.ts +3 -0
- package/build/server/register-tools.d.ts.map +1 -0
- package/build/server/register-tools.js +32 -0
- package/build/server/register-tools.js.map +1 -0
- package/build/server/resource-helpers.d.ts +21 -0
- package/build/server/resource-helpers.d.ts.map +1 -0
- package/build/server/resource-helpers.js +84 -0
- package/build/server/resource-helpers.js.map +1 -0
- package/build/services/account-manager.d.ts +88 -0
- package/build/services/account-manager.d.ts.map +1 -0
- package/build/services/account-manager.js +239 -0
- package/build/services/account-manager.js.map +1 -0
- package/build/services/claude-code-runner.d.ts +15 -0
- package/build/services/claude-code-runner.d.ts.map +1 -0
- package/build/services/claude-code-runner.js +475 -0
- package/build/services/claude-code-runner.js.map +1 -0
- package/build/services/client-context.d.ts +31 -0
- package/build/services/client-context.d.ts.map +1 -0
- package/build/services/client-context.js +44 -0
- package/build/services/client-context.js.map +1 -0
- package/build/services/exhaustion-fallback.d.ts +27 -0
- package/build/services/exhaustion-fallback.d.ts.map +1 -0
- package/build/services/exhaustion-fallback.js +30 -0
- package/build/services/exhaustion-fallback.js.map +1 -0
- package/build/services/fallback-orchestrator.d.ts +16 -0
- package/build/services/fallback-orchestrator.d.ts.map +1 -0
- package/build/services/fallback-orchestrator.js +48 -0
- package/build/services/fallback-orchestrator.js.map +1 -0
- package/build/services/opencode-client.d.ts +40 -0
- package/build/services/opencode-client.d.ts.map +1 -0
- package/build/services/opencode-client.js +147 -0
- package/build/services/opencode-client.js.map +1 -0
- package/build/services/opencode-spawner.d.ts +56 -0
- package/build/services/opencode-spawner.d.ts.map +1 -0
- package/build/services/opencode-spawner.js +426 -0
- package/build/services/opencode-spawner.js.map +1 -0
- package/build/services/output-file.d.ts +24 -0
- package/build/services/output-file.d.ts.map +1 -0
- package/build/services/output-file.js +90 -0
- package/build/services/output-file.js.map +1 -0
- package/build/services/progress-registry.d.ts +12 -0
- package/build/services/progress-registry.d.ts.map +1 -0
- package/build/services/progress-registry.js +97 -0
- package/build/services/progress-registry.js.map +1 -0
- package/build/services/question-registry.d.ts +79 -0
- package/build/services/question-registry.d.ts.map +1 -0
- package/build/services/question-registry.js +249 -0
- package/build/services/question-registry.js.map +1 -0
- package/build/services/retry-queue.d.ts +41 -0
- package/build/services/retry-queue.d.ts.map +1 -0
- package/build/services/retry-queue.js +195 -0
- package/build/services/retry-queue.js.map +1 -0
- package/build/services/sdk-client-manager.d.ts +149 -0
- package/build/services/sdk-client-manager.d.ts.map +1 -0
- package/build/services/sdk-client-manager.js +632 -0
- package/build/services/sdk-client-manager.js.map +1 -0
- package/build/services/sdk-session-adapter.d.ts +203 -0
- package/build/services/sdk-session-adapter.d.ts.map +1 -0
- package/build/services/sdk-session-adapter.js +1088 -0
- package/build/services/sdk-session-adapter.js.map +1 -0
- package/build/services/sdk-spawner.d.ts +42 -0
- package/build/services/sdk-spawner.d.ts.map +1 -0
- package/build/services/sdk-spawner.js +488 -0
- package/build/services/sdk-spawner.js.map +1 -0
- package/build/services/session-hooks.d.ts +24 -0
- package/build/services/session-hooks.d.ts.map +1 -0
- package/build/services/session-hooks.js +130 -0
- package/build/services/session-hooks.js.map +1 -0
- package/build/services/session-snapshot.d.ts +19 -0
- package/build/services/session-snapshot.d.ts.map +1 -0
- package/build/services/session-snapshot.js +203 -0
- package/build/services/session-snapshot.js.map +1 -0
- package/build/services/subscription-registry.d.ts +12 -0
- package/build/services/subscription-registry.d.ts.map +1 -0
- package/build/services/subscription-registry.js +27 -0
- package/build/services/subscription-registry.js.map +1 -0
- package/build/services/task-manager.d.ts +150 -0
- package/build/services/task-manager.d.ts.map +1 -0
- package/build/services/task-manager.js +765 -0
- package/build/services/task-manager.js.map +1 -0
- package/build/services/task-persistence.d.ts +29 -0
- package/build/services/task-persistence.d.ts.map +1 -0
- package/build/services/task-persistence.js +159 -0
- package/build/services/task-persistence.js.map +1 -0
- package/build/services/task-status-mapper.d.ts +21 -0
- package/build/services/task-status-mapper.d.ts.map +1 -0
- package/build/services/task-status-mapper.js +171 -0
- package/build/services/task-status-mapper.js.map +1 -0
- package/build/templates/index.d.ts +22 -0
- package/build/templates/index.d.ts.map +1 -0
- package/build/templates/index.js +147 -0
- package/build/templates/index.js.map +1 -0
- package/build/templates/overlays/coder-csharp.mdx +58 -0
- package/build/templates/overlays/coder-go.mdx +53 -0
- package/build/templates/overlays/coder-java.mdx +54 -0
- package/build/templates/overlays/coder-kotlin.mdx +56 -0
- package/build/templates/overlays/coder-nextjs.mdx +65 -0
- package/build/templates/overlays/coder-python.mdx +53 -0
- package/build/templates/overlays/coder-react.mdx +55 -0
- package/build/templates/overlays/coder-ruby.mdx +59 -0
- package/build/templates/overlays/coder-rust.mdx +48 -0
- package/build/templates/overlays/coder-supabase.mdx +268 -0
- package/build/templates/overlays/coder-supastarter.mdx +313 -0
- package/build/templates/overlays/coder-swift.mdx +56 -0
- package/build/templates/overlays/coder-tauri.mdx +566 -0
- package/build/templates/overlays/coder-triggerdev.mdx +296 -0
- package/build/templates/overlays/coder-typescript.mdx +45 -0
- package/build/templates/overlays/coder-vue.mdx +62 -0
- package/build/templates/overlays/planner-architecture.mdx +78 -0
- package/build/templates/overlays/planner-bugfix.mdx +36 -0
- package/build/templates/overlays/planner-feature.mdx +38 -0
- package/build/templates/overlays/planner-migration.mdx +50 -0
- package/build/templates/overlays/planner-refactor.mdx +57 -0
- package/build/templates/overlays/researcher-library.mdx +59 -0
- package/build/templates/overlays/researcher-performance.mdx +68 -0
- package/build/templates/overlays/researcher-security.mdx +86 -0
- package/build/templates/overlays/tester-graphql.mdx +191 -0
- package/build/templates/overlays/tester-playwright.mdx +621 -0
- package/build/templates/overlays/tester-rest.mdx +101 -0
- package/build/templates/overlays/tester-suite.mdx +177 -0
- package/build/templates/super-coder.mdx +529 -0
- package/build/templates/super-planner.mdx +568 -0
- package/build/templates/super-researcher.mdx +406 -0
- package/build/templates/super-tester.mdx +243 -0
- package/build/tools/answer-question.d.ts +30 -0
- package/build/tools/answer-question.d.ts.map +1 -0
- package/build/tools/answer-question.js +108 -0
- package/build/tools/answer-question.js.map +1 -0
- package/build/tools/cancel-task.d.ts +44 -0
- package/build/tools/cancel-task.d.ts.map +1 -0
- package/build/tools/cancel-task.js +144 -0
- package/build/tools/cancel-task.js.map +1 -0
- package/build/tools/send-message.d.ts +39 -0
- package/build/tools/send-message.d.ts.map +1 -0
- package/build/tools/send-message.js +124 -0
- package/build/tools/send-message.js.map +1 -0
- package/build/tools/shared-spawn.d.ts +56 -0
- package/build/tools/shared-spawn.d.ts.map +1 -0
- package/build/tools/shared-spawn.js +114 -0
- package/build/tools/shared-spawn.js.map +1 -0
- package/build/tools/spawn-agent.d.ts +85 -0
- package/build/tools/spawn-agent.d.ts.map +1 -0
- package/build/tools/spawn-agent.js +133 -0
- package/build/tools/spawn-agent.js.map +1 -0
- package/build/tools/spawn-coder.d.ts +70 -0
- package/build/tools/spawn-coder.d.ts.map +1 -0
- package/build/tools/spawn-coder.js +71 -0
- package/build/tools/spawn-coder.js.map +1 -0
- package/build/tools/spawn-planner.d.ts +70 -0
- package/build/tools/spawn-planner.d.ts.map +1 -0
- package/build/tools/spawn-planner.js +71 -0
- package/build/tools/spawn-planner.js.map +1 -0
- package/build/tools/spawn-researcher.d.ts +70 -0
- package/build/tools/spawn-researcher.d.ts.map +1 -0
- package/build/tools/spawn-researcher.js +70 -0
- package/build/tools/spawn-researcher.js.map +1 -0
- package/build/tools/spawn-task.d.ts +74 -0
- package/build/tools/spawn-task.d.ts.map +1 -0
- package/build/tools/spawn-task.js +107 -0
- package/build/tools/spawn-task.js.map +1 -0
- package/build/tools/spawn-tester.d.ts +70 -0
- package/build/tools/spawn-tester.d.ts.map +1 -0
- package/build/tools/spawn-tester.js +69 -0
- package/build/tools/spawn-tester.js.map +1 -0
- package/build/types.d.ts +101 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +28 -0
- package/build/types.js.map +1 -0
- package/build/utils/brief-validator.d.ts +30 -0
- package/build/utils/brief-validator.d.ts.map +1 -0
- package/build/utils/brief-validator.js +254 -0
- package/build/utils/brief-validator.js.map +1 -0
- package/build/utils/format.d.ts +34 -0
- package/build/utils/format.d.ts.map +1 -0
- package/build/utils/format.js +55 -0
- package/build/utils/format.js.map +1 -0
- package/build/utils/sanitize.d.ts +240 -0
- package/build/utils/sanitize.d.ts.map +1 -0
- package/build/utils/sanitize.js +89 -0
- package/build/utils/sanitize.js.map +1 -0
- package/build/utils/task-id-generator.d.ts +10 -0
- package/build/utils/task-id-generator.d.ts.map +1 -0
- package/build/utils/task-id-generator.js +22 -0
- package/build/utils/task-id-generator.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
## PLAYWRIGHT BROWSER TESTING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are testing a **web application** using Playwright via the `playwright-cli` tool. This overlay provides battle-tested patterns for browser-based E2E testing.
|
|
4
|
+
|
|
5
|
+
**Command discovery:** Run `playwright-cli --help` for all commands. Run `playwright-cli --help <command>` for details on any specific command.
|
|
6
|
+
|
|
7
|
+
**ALWAYS clean up when done:** `playwright-cli session-stop-all`
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
### BOOTSTRAP
|
|
12
|
+
|
|
13
|
+
Run this ONCE at the start of any browser testing session:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
which playwright-cli || npm install -g @anthropic-ai/playwright-cli@latest
|
|
17
|
+
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true npx playwright install chromium
|
|
18
|
+
playwright-cli session-stop 2>/dev/null # Kill stale sessions from crashed agents
|
|
19
|
+
playwright-cli config --browser=chromium
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Why each step matters:**
|
|
23
|
+
- `which` check — skip reinstall if already present
|
|
24
|
+
- `PLAYWRIGHT_SKIP_*` — prevents false install failures in containers and non-standard environments
|
|
25
|
+
- `session-stop` — a stale session from a previous run blocks everything. This is silent if nothing is running
|
|
26
|
+
- `config` — ensures chromium is the active browser
|
|
27
|
+
|
|
28
|
+
After bootstrap, `playwright-cli open <url>` will work. The session is a background daemon that persists between commands.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### TRAPS THAT WILL DERAIL YOU
|
|
33
|
+
|
|
34
|
+
Read these BEFORE your first command. These come from real testing sessions where assumptions failed. Each one will save you from getting stuck.
|
|
35
|
+
|
|
36
|
+
#### TRAP 1: Element refs die after ANY page change
|
|
37
|
+
When you run `snapshot`, you get refs like `e1`, `e23`. These refs are tied to THAT specific snapshot. After `open`, `click` that navigates, `hover`, `reload`, `tab-select`, `go-back`, or ANY action that changes the page — ALL refs are stale.
|
|
38
|
+
|
|
39
|
+
**The scariest case:** After a session restart, the same ref number (e.g. `e426`) can point to a COMPLETELY DIFFERENT element. No error — you just interact with the wrong thing.
|
|
40
|
+
|
|
41
|
+
**Rule:** After any action that might change the page, take a new `snapshot` before using refs. The safe pattern is always: `action → snapshot → use new refs`.
|
|
42
|
+
|
|
43
|
+
#### TRAP 2: `tab-new <url>` does NOT navigate
|
|
44
|
+
```bash
|
|
45
|
+
tab-new https://example.com
|
|
46
|
+
# Result: new tab opens at about:blank — NOT example.com
|
|
47
|
+
```
|
|
48
|
+
This is a silent failure — no error. You'll snapshot `about:blank` and wonder why the page is empty.
|
|
49
|
+
|
|
50
|
+
**Fix:** Always use two steps:
|
|
51
|
+
```bash
|
|
52
|
+
tab-new
|
|
53
|
+
open https://example.com
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### TRAP 3: `close` KILLS the entire session
|
|
57
|
+
```bash
|
|
58
|
+
close
|
|
59
|
+
# Result: "Session 'default' stopped." — ALL cookies, localStorage, browser state GONE
|
|
60
|
+
```
|
|
61
|
+
If you use `close` thinking you're closing a tab, you destroy everything. Any login state, any test setup — gone.
|
|
62
|
+
|
|
63
|
+
**Fix:** NEVER use `close`. Use `tab-close <index>` to close individual tabs. Use `session-stop` when you're truly done.
|
|
64
|
+
|
|
65
|
+
#### TRAP 4: console and network return FILE PATHS, not content
|
|
66
|
+
```bash
|
|
67
|
+
console error
|
|
68
|
+
# Output: "- [Console](.playwright-cli/console-xxx.log)"
|
|
69
|
+
```
|
|
70
|
+
The path IS the output. You MUST read that file to see the actual errors.
|
|
71
|
+
|
|
72
|
+
#### TRAP 5: Snapshots don't show form values or focus state
|
|
73
|
+
You filled a form with `fill e53 "John"`. The snapshot YAML will NOT show "John" in the field. You cannot verify form state by reading the snapshot.
|
|
74
|
+
|
|
75
|
+
**Fix for form values:** `eval "(el) => el.value" e53` — returns "John"
|
|
76
|
+
**Fix for focus:** `eval "() => document.activeElement?.tagName"` — snapshots never show which element has keyboard focus.
|
|
77
|
+
|
|
78
|
+
#### TRAP 6: eval only fails on DOM nodes
|
|
79
|
+
Returning DOM elements gives useless `"ref: <Node>"`. But primitives, plain objects, and arrays all work fine:
|
|
80
|
+
```bash
|
|
81
|
+
eval "() => 42" # works: 42
|
|
82
|
+
eval "() => document.title" # works: "My Page"
|
|
83
|
+
eval "() => ({ links: 92, images: 14 })" # works: { links: 92, images: 14 }
|
|
84
|
+
eval "() => [...document.querySelectorAll('a')].map(a => a.href)" # works: ["url1", ...]
|
|
85
|
+
eval "() => document.querySelectorAll('a')" # FAILS: { "0": "ref: <Node>", ... }
|
|
86
|
+
```
|
|
87
|
+
**Rule:** Don't wrap everything in `JSON.stringify()` — only use `.map()` to extract data from NodeLists.
|
|
88
|
+
|
|
89
|
+
#### TRAP 7: Multi-tab "Page URL" header is WRONG
|
|
90
|
+
When using multiple tabs, the "Page" section in snapshot output shows the WRONG tab's URL. Only the "Open tabs" section correctly shows which tab is `(current)`.
|
|
91
|
+
|
|
92
|
+
**Fix:** To verify your current URL in multi-tab mode:
|
|
93
|
+
```bash
|
|
94
|
+
eval "() => window.location.href"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### TRAP 8: Soft 404s — HTTP 200 on error pages
|
|
98
|
+
Many SPAs and Next.js sites serve 404 pages with HTTP 200 status:
|
|
99
|
+
```bash
|
|
100
|
+
run-code 'async (page) => { const r = await page.goto("https://example.com/nonexistent"); return r.status(); }'
|
|
101
|
+
# Returns: 200 — even though the page says "Not Found"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Fix:** Check page content, not HTTP status:
|
|
105
|
+
```bash
|
|
106
|
+
eval "() => document.title" # "Page Not Found | MySite"
|
|
107
|
+
eval "() => document.querySelector('h1')?.textContent" # "Lost your way?"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### TRAP 9: Dialogs block EVERYTHING
|
|
111
|
+
If a site triggers an `alert()`, `confirm()`, or `prompt()`, ALL other commands fail:
|
|
112
|
+
```
|
|
113
|
+
Error: Tool "browser_click" does not handle the modal state.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Fix:** The CLI output will show a `### Modal state` section telling you exactly what dialog is open. Dismiss it before doing anything else:
|
|
117
|
+
```bash
|
|
118
|
+
dialog-accept # OK/Accept
|
|
119
|
+
dialog-accept "value" # Accept with text (for prompt dialogs)
|
|
120
|
+
dialog-dismiss # Cancel/Dismiss
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### TRAP 10: `type` and `fill` are fundamentally different
|
|
124
|
+
- `fill <ref> <text>` — targets a specific element by ref, REPLACES all content, uses Playwright's `locator.fill()`
|
|
125
|
+
- `type <text>` — types into whatever has focus (NO ref), APPENDS to existing content, uses `keyboard.type()`
|
|
126
|
+
|
|
127
|
+
**Default to `fill` for form testing.** It's more reliable and doesn't depend on focus state. Use `type` only for keyboard-specific behavior testing.
|
|
128
|
+
|
|
129
|
+
#### TRAP 11: `fill --submit` fills THEN presses Enter
|
|
130
|
+
```bash
|
|
131
|
+
fill e53 "test@example.com" --submit
|
|
132
|
+
# Fills the field, then immediately presses Enter
|
|
133
|
+
```
|
|
134
|
+
This is a shortcut for fill + submit. Useful for search fields and login forms.
|
|
135
|
+
|
|
136
|
+
#### TRAP 12: run-code quote escaping
|
|
137
|
+
Single quotes for outer wrapper, double quotes inside:
|
|
138
|
+
```bash
|
|
139
|
+
# CORRECT:
|
|
140
|
+
run-code 'async (page) => { await page.locator("h1").textContent(); }'
|
|
141
|
+
|
|
142
|
+
# WRONG (shell eats the quotes):
|
|
143
|
+
run-code "async (page) => { await page.locator('h1').textContent(); }"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### TRAP 13: Tab index shifts after tab-close
|
|
147
|
+
When you close tab 1, the former tab 2 becomes tab 1. Use `tab-list` after closing to confirm the new order.
|
|
148
|
+
|
|
149
|
+
#### TRAP 14: network --static vs default
|
|
150
|
+
```bash
|
|
151
|
+
network # Only dynamic requests (API calls, XHR, fetch)
|
|
152
|
+
network --static # ALL resources (CSS, JS, fonts, images too)
|
|
153
|
+
```
|
|
154
|
+
Use `--static` for full resource audits. Use default for API call monitoring.
|
|
155
|
+
|
|
156
|
+
#### TRAP 15: Playwright auto-scrolls for you
|
|
157
|
+
You do NOT need to scroll to an element before clicking, filling, or hovering. Playwright scrolls to the target automatically. Only scroll manually for:
|
|
158
|
+
- Checking what's "above the fold" at different scroll positions
|
|
159
|
+
- Testing lazy-loaded content
|
|
160
|
+
- Taking viewport screenshots at specific positions
|
|
161
|
+
- Testing infinite scroll behavior
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### THE CORE TESTING LOOP
|
|
166
|
+
|
|
167
|
+
Every browser test follows this loop. Internalize it.
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
open <url>
|
|
171
|
+
↓
|
|
172
|
+
[health check: console error + network for 4xx/5xx]
|
|
173
|
+
↓
|
|
174
|
+
snapshot → get refs → interact (click, fill, etc.)
|
|
175
|
+
↓
|
|
176
|
+
[after any page change: snapshot again → get new refs]
|
|
177
|
+
↓
|
|
178
|
+
screenshot + eval → capture evidence
|
|
179
|
+
↓
|
|
180
|
+
repeat for next test step
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**The golden rule:** After ANY action that might change the page (click, navigate, hover, reload, tab-select, go-back), take a new `snapshot` before using refs.
|
|
184
|
+
|
|
185
|
+
#### Health Check Pattern
|
|
186
|
+
Run this immediately after opening any page:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
open https://example.com
|
|
190
|
+
console error # Get the log file path
|
|
191
|
+
# READ that file — look for JS errors
|
|
192
|
+
network # Get the network log path
|
|
193
|
+
# READ that file — look for failed requests (4xx, 5xx)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Use `--clear` to isolate phases:**
|
|
197
|
+
```bash
|
|
198
|
+
console --clear # Clear log before next test phase
|
|
199
|
+
network --clear # Clear log before next test phase
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### TAB-BASED TESTING — THE GOLD PATTERN
|
|
205
|
+
|
|
206
|
+
Instead of creating separate browser sessions for each test scenario, use tabs within one session. This is memory-efficient, preserves shared state (cookies, localStorage), and gives you a clear "done" signal.
|
|
207
|
+
|
|
208
|
+
#### Why tabs are superior
|
|
209
|
+
1. **One browser, multiple contexts** — 10 tabs use far less memory than 10 sessions
|
|
210
|
+
2. **Shared state** — cookies and localStorage persist across tabs, like real users
|
|
211
|
+
3. **Progress tracking** — open tabs = remaining work, closed = done
|
|
212
|
+
4. **Easy comparison** — `tab-select` between viewports instantly
|
|
213
|
+
|
|
214
|
+
#### The tab workflow
|
|
215
|
+
```bash
|
|
216
|
+
# Tab 0: Your home base (desktop, light mode)
|
|
217
|
+
open https://example.com
|
|
218
|
+
screenshot --full-page --filename=desktop-light.png
|
|
219
|
+
|
|
220
|
+
# Tab 1: Mobile
|
|
221
|
+
tab-new
|
|
222
|
+
open https://example.com # ALWAYS open after tab-new!
|
|
223
|
+
resize 375 812
|
|
224
|
+
screenshot --full-page --filename=mobile-light.png
|
|
225
|
+
|
|
226
|
+
# Tab 2: Desktop dark mode
|
|
227
|
+
tab-new
|
|
228
|
+
open https://example.com
|
|
229
|
+
run-code 'async (page) => { await page.emulateMedia({ colorScheme: "dark" }); }'
|
|
230
|
+
screenshot --full-page --filename=desktop-dark.png
|
|
231
|
+
|
|
232
|
+
# Tab 3: Mobile dark mode
|
|
233
|
+
tab-new
|
|
234
|
+
open https://example.com
|
|
235
|
+
resize 375 812
|
|
236
|
+
run-code 'async (page) => { await page.emulateMedia({ colorScheme: "dark" }); }'
|
|
237
|
+
screenshot --full-page --filename=mobile-dark.png
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### Working with tabs
|
|
241
|
+
```bash
|
|
242
|
+
tab-list # See all tabs with indexes and URLs
|
|
243
|
+
tab-select <index> # Switch to a specific tab
|
|
244
|
+
tab-close <index> # Close a tab (NOT close! close kills the session)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Tab completion signal
|
|
248
|
+
- All test tabs open = all scenarios in progress
|
|
249
|
+
- Tab closed = that scenario is complete
|
|
250
|
+
- Only tab 0 remains = ALL testing complete
|
|
251
|
+
|
|
252
|
+
#### Critical tab gotchas
|
|
253
|
+
- `tab-new <url>` opens about:blank — ALWAYS follow with `open <url>`
|
|
254
|
+
- "Page URL" in snapshot is wrong when multiple tabs are open — trust "Open tabs" section
|
|
255
|
+
- After `tab-close`, remaining tab indexes shift — use `tab-list` to re-orient
|
|
256
|
+
- NEVER use `close` — it kills the session. ALWAYS use `tab-close <index>`
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### MULTI-VIEWPORT TESTING
|
|
261
|
+
|
|
262
|
+
#### Standard breakpoints
|
|
263
|
+
| Device | Width | Height |
|
|
264
|
+
|--------|-------|--------|
|
|
265
|
+
| Desktop | 1280 | 720 |
|
|
266
|
+
| Tablet | 768 | 1024 |
|
|
267
|
+
| Mobile | 375 | 812 |
|
|
268
|
+
|
|
269
|
+
#### Single-page approach (when you just need screenshots)
|
|
270
|
+
```bash
|
|
271
|
+
open https://example.com
|
|
272
|
+
screenshot --full-page --filename=desktop.png
|
|
273
|
+
|
|
274
|
+
resize 768 1024
|
|
275
|
+
screenshot --full-page --filename=tablet.png
|
|
276
|
+
|
|
277
|
+
resize 375 812
|
|
278
|
+
screenshot --full-page --filename=mobile.png
|
|
279
|
+
|
|
280
|
+
resize 1280 720 # Reset to desktop
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Multi-tab approach (when you need to compare or interact)
|
|
284
|
+
Use the tab workflow above — one tab per viewport. This lets you switch between viewports to compare specific elements.
|
|
285
|
+
|
|
286
|
+
#### What to check at each viewport
|
|
287
|
+
1. **Layout** — does content reflow properly? No horizontal overflow?
|
|
288
|
+
```bash
|
|
289
|
+
eval "() => ({ hasHScroll: document.body.scrollWidth > window.innerWidth })"
|
|
290
|
+
```
|
|
291
|
+
2. **Navigation** — is the hamburger menu working? Are nav items accessible?
|
|
292
|
+
3. **Text** — is text readable? No truncation?
|
|
293
|
+
4. **Interactive elements** — are buttons large enough to tap? No overlapping clickables?
|
|
294
|
+
5. **Images** — do they scale properly? Any broken images?
|
|
295
|
+
|
|
296
|
+
#### Automated breakpoint sweep (for comprehensive audits)
|
|
297
|
+
```bash
|
|
298
|
+
run-code 'async (page) => {
|
|
299
|
+
const breakpoints = [320, 375, 425, 768, 1024, 1280, 1440, 1920];
|
|
300
|
+
for (const w of breakpoints) {
|
|
301
|
+
await page.setViewportSize({ width: w, height: 800 });
|
|
302
|
+
await page.screenshot({ fullPage: true, path: `.playwright-cli/responsive-${w}.png` });
|
|
303
|
+
}
|
|
304
|
+
return "Done: " + breakpoints.length + " screenshots at all breakpoints";
|
|
305
|
+
}'
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### DARK MODE TESTING
|
|
311
|
+
|
|
312
|
+
Dark mode is a standard feature now. When testing UI, you should check both light and dark variants.
|
|
313
|
+
|
|
314
|
+
#### Approach hierarchy — try in this order
|
|
315
|
+
Different sites implement dark mode differently. Try these approaches in order until one works:
|
|
316
|
+
|
|
317
|
+
**1. System preference emulation (MOST RELIABLE — works for standards-compliant sites):**
|
|
318
|
+
```bash
|
|
319
|
+
run-code 'async (page) => { await page.emulateMedia({ colorScheme: "dark" }); }'
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**2. Check if emulation worked — if not, try class-based themes:**
|
|
323
|
+
```bash
|
|
324
|
+
# Check what CSS classes the site uses
|
|
325
|
+
eval "() => document.documentElement.className"
|
|
326
|
+
# If Tailwind/Next.js themes: add the class
|
|
327
|
+
eval "() => document.documentElement.classList.add('dark')"
|
|
328
|
+
# Or data-attribute based:
|
|
329
|
+
eval "() => document.documentElement.setAttribute('data-theme', 'dark')"
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**3. If no class-based theme, look for a toggle in the snapshot:**
|
|
333
|
+
```bash
|
|
334
|
+
snapshot
|
|
335
|
+
# Find a theme toggle button, then click it
|
|
336
|
+
click <toggle-ref>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**4. If no toggle visible, check localStorage:**
|
|
340
|
+
```bash
|
|
341
|
+
eval "() => JSON.stringify(localStorage)"
|
|
342
|
+
# Look for theme-related keys and set them:
|
|
343
|
+
eval "() => { localStorage.setItem('theme', 'dark'); location.reload(); }"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### The four-screenshot matrix
|
|
347
|
+
For comprehensive visual testing, capture all combinations:
|
|
348
|
+
|
|
349
|
+
| Viewport | Theme | Filename |
|
|
350
|
+
|----------|-------|----------|
|
|
351
|
+
| Desktop (1280x720) | Light | `desktop-light.png` |
|
|
352
|
+
| Desktop (1280x720) | Dark | `desktop-dark.png` |
|
|
353
|
+
| Mobile (375x812) | Light | `mobile-light.png` |
|
|
354
|
+
| Mobile (375x812) | Dark | `mobile-dark.png` |
|
|
355
|
+
|
|
356
|
+
Use the tab workflow to set up all four scenarios efficiently.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
### SCREENSHOT STRATEGY
|
|
361
|
+
|
|
362
|
+
#### Three screenshot modes
|
|
363
|
+
|
|
364
|
+
**1. Full page** — entire scrollable page in one image:
|
|
365
|
+
```bash
|
|
366
|
+
screenshot --full-page --filename=homepage-full.png
|
|
367
|
+
```
|
|
368
|
+
Use for: visual baselines, layout overview, content audit, initial assessment.
|
|
369
|
+
|
|
370
|
+
**2. Viewport only** — just what's visible in current viewport:
|
|
371
|
+
```bash
|
|
372
|
+
screenshot --filename=above-the-fold.png
|
|
373
|
+
```
|
|
374
|
+
Use for: above-the-fold checks, specific sections after scrolling, detail inspection.
|
|
375
|
+
|
|
376
|
+
**3. Element** — just one element:
|
|
377
|
+
```bash
|
|
378
|
+
screenshot e426 --filename=login-form.png
|
|
379
|
+
```
|
|
380
|
+
Use for: form states, button styles, component-level comparisons. Saved as `element-*.png`.
|
|
381
|
+
|
|
382
|
+
#### Use `--filename` for predictable names
|
|
383
|
+
Without it, screenshots get auto-generated timestamps. Named files are easier to reference in reports.
|
|
384
|
+
|
|
385
|
+
#### Scroll-and-snap pattern (fold-by-fold inspection)
|
|
386
|
+
```bash
|
|
387
|
+
screenshot --filename=fold-1.png
|
|
388
|
+
mousewheel 0 720
|
|
389
|
+
screenshot --filename=fold-2.png
|
|
390
|
+
mousewheel 0 720
|
|
391
|
+
screenshot --filename=fold-3.png
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
### FORM TESTING
|
|
397
|
+
|
|
398
|
+
#### The reliable pattern: fill → verify → screenshot → submit
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
# 1. Fill all fields using fill (not type)
|
|
402
|
+
fill e53 "John"
|
|
403
|
+
fill e56 "Doe"
|
|
404
|
+
fill e59 "john@example.com"
|
|
405
|
+
fill e62 "Acme Corp"
|
|
406
|
+
|
|
407
|
+
# 2. Verify values were set (snapshots DON'T show form values!)
|
|
408
|
+
eval "() => {
|
|
409
|
+
const inputs = document.querySelectorAll('input[type=text], input[type=email]');
|
|
410
|
+
return Array.from(inputs).map(i => ({ name: i.name, value: i.value }));
|
|
411
|
+
}"
|
|
412
|
+
|
|
413
|
+
# 3. Screenshot the filled form (visual evidence)
|
|
414
|
+
screenshot --filename=form-filled.png
|
|
415
|
+
|
|
416
|
+
# 4. Submit
|
|
417
|
+
click e64 # Click submit button
|
|
418
|
+
# Or: fill e62 "Acme Corp" --submit # Fill last field + press Enter
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### When to use `fill` vs `type`
|
|
422
|
+
- **fill** — for setting form field values. Cleaner, more reliable, targets by ref, REPLACES content
|
|
423
|
+
- **type** — for testing keyboard behavior. Appends to focused element, tests autocomplete triggers, input event handlers
|
|
424
|
+
|
|
425
|
+
#### Verifying form state
|
|
426
|
+
**Snapshots don't show input values.** You MUST use eval:
|
|
427
|
+
```bash
|
|
428
|
+
eval "(el) => el.value" e53 # Check one field
|
|
429
|
+
eval "(el) => el.checked" e72 # Check checkbox
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### Select dropdowns and file uploads
|
|
433
|
+
```bash
|
|
434
|
+
select e80 "option-value" # Select dropdown option
|
|
435
|
+
upload /path/to/file.pdf # Upload a file
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### EVAL & RUN-CODE — YOUR POWER TOOLS
|
|
441
|
+
|
|
442
|
+
#### eval: quick data extraction
|
|
443
|
+
|
|
444
|
+
Without ref — runs on page (window context):
|
|
445
|
+
```bash
|
|
446
|
+
eval "() => document.title"
|
|
447
|
+
eval "() => window.location.href"
|
|
448
|
+
eval "() => document.querySelectorAll('a').length"
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
With ref — function receives that element:
|
|
452
|
+
```bash
|
|
453
|
+
eval "(el) => el.value" e53 # Input value
|
|
454
|
+
eval "(el) => getComputedStyle(el).fontSize" e156 # CSS property
|
|
455
|
+
eval "(el) => el.getBoundingClientRect()" e9 # Dimensions
|
|
456
|
+
eval "(el) => el.getAttribute('aria-label')" e42 # Attribute
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### run-code: full Playwright API
|
|
460
|
+
|
|
461
|
+
When the CLI commands aren't enough, `run-code` gives you the full `page` object:
|
|
462
|
+
|
|
463
|
+
**Response interception:**
|
|
464
|
+
```bash
|
|
465
|
+
run-code 'async (page) => {
|
|
466
|
+
let calls = [];
|
|
467
|
+
page.on("response", r => {
|
|
468
|
+
if (r.url().includes("api")) calls.push({ url: r.url(), status: r.status() });
|
|
469
|
+
});
|
|
470
|
+
await page.reload();
|
|
471
|
+
await page.waitForTimeout(2000);
|
|
472
|
+
return calls;
|
|
473
|
+
}'
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**Wait for specific conditions:**
|
|
477
|
+
```bash
|
|
478
|
+
run-code 'async (page) => {
|
|
479
|
+
await page.waitForSelector(".loading-spinner", { state: "hidden" });
|
|
480
|
+
return "page loaded";
|
|
481
|
+
}'
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Cookie manipulation:**
|
|
485
|
+
```bash
|
|
486
|
+
run-code 'async (page) => {
|
|
487
|
+
const ctx = page.context();
|
|
488
|
+
await ctx.addCookies([{ name: "test", value: "123", url: "https://example.com" }]);
|
|
489
|
+
return "cookie set";
|
|
490
|
+
}'
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Rule:** Use CLI commands for common operations (click, fill, screenshot). Use `run-code` for things CLI commands can't do.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
### VERIFICATION PATTERNS
|
|
498
|
+
|
|
499
|
+
When you need to verify something, don't guess — use the right method.
|
|
500
|
+
|
|
501
|
+
#### Verifying navigation succeeded
|
|
502
|
+
```
|
|
503
|
+
1. eval "() => window.location.href" ← ground truth
|
|
504
|
+
2. Check "Open tabs" section (NOT "Page URL" header in multi-tab mode)
|
|
505
|
+
3. eval "() => document.title"
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### Checking for errors
|
|
509
|
+
```
|
|
510
|
+
1. Check page content (catches soft 404s):
|
|
511
|
+
eval "() => document.title"
|
|
512
|
+
|
|
513
|
+
2. Check HTTP status (catches hard errors):
|
|
514
|
+
run-code 'async (page) => { const r = await page.goto(url); return r.status(); }'
|
|
515
|
+
|
|
516
|
+
3. Check console for JavaScript errors:
|
|
517
|
+
console error → read the log file
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
#### Verifying an element exists and is visible
|
|
521
|
+
```
|
|
522
|
+
1. Check snapshot for the element
|
|
523
|
+
2. If not in snapshot: eval "() => document.querySelector('#myElement') !== null"
|
|
524
|
+
3. Check visibility: eval "(el) => { const r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0; }" <ref>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Verifying form submission worked
|
|
528
|
+
```
|
|
529
|
+
1. Check URL changed: eval "() => window.location.href"
|
|
530
|
+
2. Check for success message in snapshot
|
|
531
|
+
3. Check network log for the submission request
|
|
532
|
+
4. Check console for errors
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
### WHEN THINGS GO WRONG — SELF-RECOVERY
|
|
538
|
+
|
|
539
|
+
These are the patterns where agents derail. If you find yourself stuck, check this section.
|
|
540
|
+
|
|
541
|
+
#### "Ref not found" errors
|
|
542
|
+
**Cause:** Refs are stale. You did something that changed the page since your last snapshot.
|
|
543
|
+
**Fix:** Run `snapshot` to get fresh refs. Then use the new refs.
|
|
544
|
+
|
|
545
|
+
#### All commands fail with "does not handle modal state"
|
|
546
|
+
**Cause:** A dialog (alert/confirm/prompt) is blocking the page.
|
|
547
|
+
**Fix:** Run `dialog-accept` or `dialog-dismiss`. Then continue.
|
|
548
|
+
|
|
549
|
+
#### Page is blank / empty snapshot
|
|
550
|
+
**Cause 1:** You used `tab-new` without `open`. Tab is at `about:blank`.
|
|
551
|
+
**Fix:** Run `open <url>`.
|
|
552
|
+
|
|
553
|
+
**Cause 2:** Page is still loading.
|
|
554
|
+
**Fix:** `run-code 'async (page) => { await page.waitForSelector("body > *"); return "loaded"; }'`
|
|
555
|
+
|
|
556
|
+
#### Session died unexpectedly
|
|
557
|
+
**Cause:** You used `close` instead of `tab-close`, or the session crashed.
|
|
558
|
+
**Fix:** Run the bootstrap sequence again:
|
|
559
|
+
```bash
|
|
560
|
+
playwright-cli session-stop 2>/dev/null
|
|
561
|
+
playwright-cli config --browser=chromium
|
|
562
|
+
playwright-cli open <url>
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
#### Command behaves unexpectedly
|
|
566
|
+
**Fix:** Run `playwright-cli --help <command>` to see the exact syntax and flags. Don't assume — verify.
|
|
567
|
+
|
|
568
|
+
#### You're stuck in a loop
|
|
569
|
+
**Fix:** Stop. Use `sequential_thinking` to analyze what went wrong. Often the issue is stale refs, a dialog, or wrong URL.
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
### VIDEO & TRACING
|
|
574
|
+
|
|
575
|
+
#### Video recording (for human stakeholders)
|
|
576
|
+
```bash
|
|
577
|
+
video-start # Start recording
|
|
578
|
+
# ... do your testing ...
|
|
579
|
+
video-stop # Stop and save → .playwright-cli/video-*.webm
|
|
580
|
+
```
|
|
581
|
+
Video is for humans — LLMs can't process .webm files. For your own analysis, prefer screenshots + text notes at key moments.
|
|
582
|
+
|
|
583
|
+
#### Tracing (for performance debugging)
|
|
584
|
+
```bash
|
|
585
|
+
tracing-start # Start trace
|
|
586
|
+
# ... do actions ...
|
|
587
|
+
tracing-stop # Stop → .playwright-cli/traces/trace-*.trace
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
#### PDF generation (for print testing)
|
|
591
|
+
```bash
|
|
592
|
+
pdf # Save page as PDF → .playwright-cli/page-*.pdf
|
|
593
|
+
```
|
|
594
|
+
Only works in Chromium. Uses print stylesheet. Useful for testing print layouts or generating report artifacts.
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
### PLAYWRIGHT-SPECIFIC RULES
|
|
599
|
+
|
|
600
|
+
#### ALWAYS
|
|
601
|
+
- Run `snapshot` after any page-changing action before using refs
|
|
602
|
+
- Use `fill` (not `type`) for setting form field values
|
|
603
|
+
- Use `tab-close <index>` (NEVER `close`) to close tabs
|
|
604
|
+
- Use `eval` to verify form values and current URL (not snapshot text)
|
|
605
|
+
- Use `--help <command>` when unsure about syntax
|
|
606
|
+
- Clean up: `session-stop-all` when done
|
|
607
|
+
|
|
608
|
+
#### NEVER
|
|
609
|
+
- Use stale refs — always re-snapshot after page changes
|
|
610
|
+
- Trust "Page URL" in snapshot when multiple tabs are open
|
|
611
|
+
- Trust HTTP status codes for 404 detection on SPAs
|
|
612
|
+
- Use `close` to close a tab — it kills the session
|
|
613
|
+
- Assume `tab-new <url>` navigates — it opens about:blank
|
|
614
|
+
|
|
615
|
+
#### SELF-CHECK
|
|
616
|
+
If you're stuck or confused:
|
|
617
|
+
1. Check for dialogs blocking you (`dialog-accept` / `dialog-dismiss`)
|
|
618
|
+
2. Check if your refs are stale (run `snapshot`)
|
|
619
|
+
3. Check which tab you're on (`tab-list` + `eval "() => window.location.href"`)
|
|
620
|
+
4. Check `--help <command>` for correct syntax
|
|
621
|
+
5. Use `sequential_thinking` to step back and analyze
|