openspec-playwright 0.2.9 → 0.3.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/.claude/skills/openspec-e2e/SKILL.md +51 -45
- package/README.md +15 -17
- package/README.zh-CN.md +15 -17
- package/employee-standards.md +82 -21
- package/package.json +1 -1
- package/templates/test-plan.md +1 -1
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
name: openspec-e2e
|
|
3
3
|
description: Run Playwright E2E verification for an OpenSpec change. Use when the user wants to validate that the implementation works end-to-end by running Playwright tests generated from the specs.
|
|
4
4
|
license: MIT
|
|
5
|
-
compatibility: Requires openspec CLI, Playwright (with browsers installed), and @playwright/mcp (globally installed via `claude mcp add playwright npx @playwright/mcp@latest
|
|
5
|
+
compatibility: Requires openspec CLI, Playwright (with browsers installed), /browse (gstack, for exploration), and @playwright/mcp (globally installed via `claude mcp add playwright npx @playwright/mcp@latest`, for test execution + Healer).
|
|
6
6
|
metadata:
|
|
7
7
|
author: openspec-playwright
|
|
8
|
-
version: "2.
|
|
8
|
+
version: "2.24"
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Input
|
|
@@ -44,13 +44,7 @@ Both modes update `app-knowledge.md` and `app-exploration.md`. All `.spec.ts` fi
|
|
|
44
44
|
用户操作 → 浏览器 UI → 后端 → 数据库 → UI 反馈
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
**API only as fallback** —
|
|
48
|
-
|
|
49
|
-
- Triggering HTTP 5xx/4xx error responses (hard to reach via UI)
|
|
50
|
-
- Edge cases requiring pre-condition data that UI cannot set up
|
|
51
|
-
- Cases where Step 4 exploration confirmed no UI element exists
|
|
52
|
-
|
|
53
|
-
**Setup vs Assertion**: API is acceptable for **setup/precondition** (preparing test data). Every **final assertion** about visible UI state must use UI selectors — never use `page.request` to assert something the user can see on screen.
|
|
47
|
+
**API only as fallback** — See **Mock data rule** below. `page.request` is acceptable for pre-condition setup (preparing test data) and API-level mocking via `page.route()`. Every **final assertion** about visible UI state must use UI selectors — never use `page.request` to assert something the user can see on screen.
|
|
54
48
|
|
|
55
49
|
**Decision rule (per assertion)**:
|
|
56
50
|
|
|
@@ -71,7 +65,24 @@ Is the assertion about a computed/counted/calculated value?
|
|
|
71
65
|
→ No → UI assertion is sufficient
|
|
72
66
|
```
|
|
73
67
|
|
|
74
|
-
**
|
|
68
|
+
**Mock data rule:**
|
|
69
|
+
|
|
70
|
+
- **Frontend: forbidden.** UI interactions must use real browser + real app data. Mocking frontend code (JS variables, component state, module-level stubs) hides real integration issues. If the frontend cannot reach a scenario through normal UI flow → **ask the user**.
|
|
71
|
+
- **API: allowed at HTTP level.** Use `page.route()` to intercept and mock API responses (status codes, body data, latency) when:
|
|
72
|
+
- Triggering HTTP 5xx/4xx error responses (hard to reach via UI)
|
|
73
|
+
- Edge cases requiring pre-condition data that UI cannot set up
|
|
74
|
+
- Third-party API failures (payment, SMS, email providers)
|
|
75
|
+
- **Scope: API level only** — `page.route()` intercepts HTTP; do NOT mock at the database or backend service level. Mocking below the HTTP layer bypasses the real API contract and produces false confidence.
|
|
76
|
+
- **User consent required.** Before using `page.route()` mocking, stop and ask:
|
|
77
|
+
```
|
|
78
|
+
API mocking needed for: <reason>
|
|
79
|
+
Mocked endpoint: <URL or pattern>
|
|
80
|
+
Expected behavior: <what the test verifies>
|
|
81
|
+
Reply **yes** to proceed, or tell me to find a UI-based approach instead.
|
|
82
|
+
```
|
|
83
|
+
If the user says no → attempt a UI-based approach or skip that test case.
|
|
84
|
+
|
|
85
|
+
**Examples where API assertion is required:
|
|
75
86
|
|
|
76
87
|
```typescript
|
|
77
88
|
// ❌ UI-only assertion — hides calculation bugs
|
|
@@ -118,8 +129,8 @@ expect((await post.json()).likeCount).toBeGreaterThan(0); // verify persistence
|
|
|
118
129
|
- Announce: "Mode: full app exploration + Page Object discovery"
|
|
119
130
|
- **Goal**: Discover new routes, extract selectors, and build `pages/*.ts` Page Objects — accumulated asset for future Change tests
|
|
120
131
|
- **Route discovery** (in order):
|
|
121
|
-
1. **sitemap.xml**:
|
|
122
|
-
2. **Link extraction**: Navigate to `${BASE_URL}/` → `
|
|
132
|
+
1. **sitemap.xml**: `$B goto ${BASE_URL}/sitemap.xml` → parse URLs
|
|
133
|
+
2. **Link extraction**: Navigate to `${BASE_URL}/` → `$B js` extracts all `<a href>`:
|
|
123
134
|
```javascript
|
|
124
135
|
// Extract all internal links from current page
|
|
125
136
|
() => {
|
|
@@ -188,16 +199,16 @@ Explore to collect real DOM data before writing test plan. This eliminates blind
|
|
|
188
199
|
|
|
189
200
|
#### 4.1. Verify BASE_URL + Read app-knowledge.md
|
|
190
201
|
|
|
191
|
-
1. **Verify BASE_URL**:
|
|
202
|
+
1. **Verify BASE_URL**: `$B goto <BASE_URL>` → if HTTP 5xx → **STOP: backend error. Fix app first.**
|
|
192
203
|
2. **Read app-knowledge.md**: known risks, project conventions
|
|
193
204
|
3. **Routes** (from Step 1): use already-discovered routes — no need to re-extract
|
|
194
205
|
|
|
195
|
-
#### 4.2. Explore each route via
|
|
206
|
+
#### 4.2. Explore each route via /browse
|
|
196
207
|
|
|
197
208
|
For each route:
|
|
198
209
|
|
|
199
210
|
```
|
|
200
|
-
|
|
211
|
+
$B goto <url> → $B console → $B snapshot → $B screenshot
|
|
201
212
|
```
|
|
202
213
|
|
|
203
214
|
**After navigating, check for app-level errors**:
|
|
@@ -214,43 +225,42 @@ browser_navigate → browser_console_messages → browser_snapshot → browser_t
|
|
|
214
225
|
|
|
215
226
|
```
|
|
216
227
|
// 1. Initial capture
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
228
|
+
$B goto <url>
|
|
229
|
+
$B wait --networkidle // wait for SPA hydration
|
|
230
|
+
$B js "window.location.href" // url1
|
|
231
|
+
$B wait 2000
|
|
220
232
|
|
|
221
233
|
// 2. Observe stability
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const msgs = await browser_console_messages();
|
|
234
|
+
$B js "window.location.href" // url2
|
|
235
|
+
$B console --errors
|
|
225
236
|
|
|
226
237
|
// 3. Detect
|
|
227
238
|
if (url1 !== url2) {
|
|
228
|
-
→ ❌ URL changed — redirect loop
|
|
229
|
-
→ Is this route protected without valid auth
|
|
239
|
+
→ ❌ URL changed — redirect loop
|
|
240
|
+
→ Is this route protected without valid auth?
|
|
230
241
|
→ Yes → auth.setup.ts is broken → fix auth first
|
|
231
242
|
→ No → App middleware bug → mark route ❌ skip, record as App Bug
|
|
232
243
|
}
|
|
233
|
-
if (
|
|
244
|
+
if (console errors/warnings > 10) {
|
|
234
245
|
→ ❌ Excessive console errors — page refresh / JS crash loop
|
|
235
246
|
→ Mark route ❌ skip, record as App Bug
|
|
236
247
|
}
|
|
237
248
|
```
|
|
238
249
|
|
|
239
|
-
**Network monitoring**: After navigating, use `
|
|
250
|
+
**Network monitoring**: After navigating, use `$B network` to check for failed API calls. Failed requests (status ≥ 400) on a route indicate an API/backend issue — record in `app-exploration.md` for reference.
|
|
240
251
|
|
|
241
252
|
**For guest routes** (no auth):
|
|
242
253
|
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
await browser_navigate(`${BASE_URL}/<route>`);
|
|
254
|
+
```
|
|
255
|
+
$B goto <url>
|
|
246
256
|
```
|
|
247
257
|
|
|
248
258
|
**For protected routes** (auth required):
|
|
249
259
|
|
|
250
|
-
```
|
|
260
|
+
```
|
|
251
261
|
// Option A: use existing storageState (recommended)
|
|
252
262
|
// Option B: navigate to /login first, fill form, then navigate to target
|
|
253
|
-
// Option C:
|
|
263
|
+
// Option C: $B cookie to set auth cookies directly
|
|
254
264
|
```
|
|
255
265
|
|
|
256
266
|
**If credentials are not yet available**:
|
|
@@ -268,7 +278,7 @@ Wait for page stability:
|
|
|
268
278
|
|
|
269
279
|
#### 4.3. Parse the snapshot
|
|
270
280
|
|
|
271
|
-
From `
|
|
281
|
+
From `$B snapshot` output, extract **interactive elements** for each route:
|
|
272
282
|
|
|
273
283
|
| Element type | What to capture | Selector priority |
|
|
274
284
|
| -------------------- | ------------------------------------ | ---------------------------------------------------------- |
|
|
@@ -282,7 +292,7 @@ From `browser_snapshot` output, extract **interactive elements** for each route:
|
|
|
282
292
|
|
|
283
293
|
#### 4.3.1. Detect special elements
|
|
284
294
|
|
|
285
|
-
From `
|
|
295
|
+
From `$B snapshot` + `$B js`, identify these special elements per route:
|
|
286
296
|
|
|
287
297
|
**Special element detection matrix:**
|
|
288
298
|
|
|
@@ -299,9 +309,9 @@ From `browser_snapshot` + `browser_evaluate`, identify these special elements pe
|
|
|
299
309
|
| Drag-and-drop | drag events in JS | Simulate DnD via coordinate clicks | Low |
|
|
300
310
|
| Date picker | specific `data-testid` or class patterns | Click triggers → evaluate value | Low (skip unless specs mention) |
|
|
301
311
|
| Infinite scroll | Dynamic row insertion | Count elements before/after scroll | Low (skip unless specs mention dynamic lists/pagination) |
|
|
302
|
-
| WebSocket / SSE | No DOM signal | Check `
|
|
312
|
+
| WebSocket / SSE | No DOM signal | Check `$B console --errors` for WS events | Low (check only if app uses real-time features) |
|
|
303
313
|
|
|
304
|
-
**For each detected special element, capture via `
|
|
314
|
+
**For each detected special element, capture via `$B js` with targeted DOM queries:**
|
|
305
315
|
- Canvas: `getContext('webgl2'/'webgl'/'2d')`, `width`, `height`
|
|
306
316
|
- Iframe: `src` attribute → use `frameLocator` in tests
|
|
307
317
|
- CAPTCHA: `.g-recaptcha`, `.h-captcha`, `[data-sitekey]`, canvas+slider detection
|
|
@@ -316,8 +326,6 @@ Record findings in `app-exploration.md` → **Special Elements Detected** table.
|
|
|
316
326
|
|
|
317
327
|
Output: `openspec/changes/<name>/specs/playwright/app-exploration.md`
|
|
318
328
|
|
|
319
|
-
Template: read from `.claude/skills/openspec-e2e/templates/app-exploration.md` (project-local skill directory)
|
|
320
|
-
|
|
321
329
|
Key fields per route:
|
|
322
330
|
|
|
323
331
|
- **URL**: `${BASE_URL}<path>`
|
|
@@ -383,7 +391,7 @@ Reply **yes** to proceed, or tell me to exclude routes or adjust strategies.
|
|
|
383
391
|
|
|
384
392
|
**Create test cases**: functional requirement → test case, with `@role` and `@auth` tags. Reference verified selectors from app-exploration.md.
|
|
385
393
|
|
|
386
|
-
|
|
394
|
+
If a test case requires `page.route()` API mocking → append `⚠️ API Mock` flag to the test case line in the summary, with reason.
|
|
387
395
|
|
|
388
396
|
**Idempotency**: If test-plan.md exists → read and use, **but you MAY supplement missing test cases**. "Do not regenerate" means: do not discard existing cases, but you CAN add new ones discovered during Step 4 exploration that weren't in the original spec (e.g., empty states, error paths found during DOM exploration).
|
|
389
397
|
|
|
@@ -430,8 +438,6 @@ If the user requests changes → update test-plan.md → re-display summary →
|
|
|
430
438
|
|
|
431
439
|
**Page Object pattern** — read before writing any page file:
|
|
432
440
|
|
|
433
|
-
Read: `.claude/skills/openspec-e2e/templates/e2e-test.ts` → LoginPage example
|
|
434
|
-
|
|
435
441
|
```typescript
|
|
436
442
|
// ✅ 正确:getters + async actions + this.click/fill
|
|
437
443
|
export class LoginPage extends BasePage {
|
|
@@ -497,7 +503,7 @@ Is this assertion about a visible UI result?
|
|
|
497
503
|
|
|
498
504
|
**Test coverage — empty states**: For list/detail pages, explore the empty state. If the app shows a "no data" UI when the list is empty, generate a test to verify it. Empty states are often missing from specs but are real user paths.
|
|
499
505
|
|
|
500
|
-
**Test coverage — special elements**: Check `app-exploration.md` → **Special Elements Detected** table. For each special element, generate tests using
|
|
506
|
+
**Test coverage — special elements**: Check `app-exploration.md` → **Special Elements Detected** table. For each special element, generate tests using the following strategies:
|
|
501
507
|
- Canvas: screenshot + boundingBox → dimensions > 0, or 2D pixel verification
|
|
502
508
|
- WebGL: screenshot only (no pixel comparison — rendering varies)
|
|
503
509
|
- Iframe: `frameLocator` + assert inner content visible
|
|
@@ -508,7 +514,7 @@ Is this assertion about a visible UI result?
|
|
|
508
514
|
**Test coverage — AI-opaque elements**: For CAPTCHA, OTP, slider CAPTCHA, file upload, and drag-drop — elements that Playwright cannot reliably automate:
|
|
509
515
|
|
|
510
516
|
1. Mark the element in `app-exploration.md` → **Special Elements Detected** table with type and automation strategy
|
|
511
|
-
2. Generate the test using the appropriate strategy
|
|
517
|
+
2. Generate the test using the appropriate strategy:
|
|
512
518
|
- **CAPTCHA**: Bypass via `auth.setup.ts` storageState, or skip with `test.skip()`, or verify via API
|
|
513
519
|
- **OTP**: Use pre-verified test credentials (`E2E_OTP_CODE` env var), or development bypass flag
|
|
514
520
|
- **File upload**: Use `page.setInputFiles()` with fixture files
|
|
@@ -586,7 +592,7 @@ test('user can login', async ({ page }) => {
|
|
|
586
592
|
| `getByRole`, `getByTestId`, `getByLabel` | CSS class (`'.notification-bell'`), CSS ID (`'#avatarBtn'`) |
|
|
587
593
|
| `waitForSelector(targetElement)` | hardcoded `200ms` / `500ms` delays |
|
|
588
594
|
|
|
589
|
-
See
|
|
595
|
+
See above for Page Object pattern, LoginPage example, and BasePage utilities.
|
|
590
596
|
|
|
591
597
|
If the file exists → diff against test-plan, add only missing test cases.
|
|
592
598
|
|
|
@@ -615,13 +621,13 @@ Auth required. To set up:
|
|
|
615
621
|
|
|
616
622
|
**Idempotency**: If `auth.setup.ts` already exists → verify format, update only if stale.
|
|
617
623
|
|
|
618
|
-
**Post-auth re-exploration**: If Step 4 skipped protected routes due to missing auth, re-run exploration for those routes now that auth is configured. Navigate to each protected route with auth context → `
|
|
624
|
+
**Post-auth re-exploration**: If Step 4 skipped protected routes due to missing auth, re-run exploration for those routes now that auth is configured. Navigate to each protected route with auth context → `$B snapshot` → update `app-exploration.md`. Selectors verified now are better than guesses used during test generation.
|
|
619
625
|
|
|
620
626
|
### 8. Configure playwright.config.ts
|
|
621
627
|
|
|
622
628
|
**Output**: `playwright.config.ts` (project root; or `tests/playwright/playwright.config.ts` if config already exists there)
|
|
623
629
|
|
|
624
|
-
If missing → generate
|
|
630
|
+
If missing → generate a minimal `playwright.config.ts` with webServer, projects, and reporters.
|
|
625
631
|
|
|
626
632
|
**Auto-detect BASE_URL** (in priority order):
|
|
627
633
|
|
|
@@ -882,7 +888,7 @@ Read report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`. Present:
|
|
|
882
888
|
- Human Escalations (if any, with user decision)
|
|
883
889
|
- Recommendations with `file:line` references
|
|
884
890
|
|
|
885
|
-
|
|
891
|
+
Generate report based on the structure described in Step 11.
|
|
886
892
|
|
|
887
893
|
**Update tasks.md**:
|
|
888
894
|
- If 0 active App Bugs → find E2E-related items, append `✅ Verified via Playwright E2E (<timestamp>)`.
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ openspec-pw init # Install Playwright E2E integration
|
|
|
20
20
|
|
|
21
21
|
## Supported AI Coding Assistants
|
|
22
22
|
|
|
23
|
-
Claude Code — E2E workflow is driven by SKILL.md using Playwright MCP
|
|
23
|
+
Claude Code — E2E workflow is driven by SKILL.md using /browse (exploration) + Playwright MCP (test execution).
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
@@ -52,7 +52,7 @@ openspec-pw uninstall # Remove integration from the project
|
|
|
52
52
|
│
|
|
53
53
|
├── 3. Validate env → run seed.spec.ts
|
|
54
54
|
│
|
|
55
|
-
├── 4. Explore app →
|
|
55
|
+
├── 4. Explore app → /browse explores real DOM
|
|
56
56
|
│ ├─ Read app-knowledge.md (project-level knowledge)
|
|
57
57
|
│ ├─ Extract routes from specs
|
|
58
58
|
│ ├─ Navigate each route → snapshot → screenshot
|
|
@@ -77,13 +77,10 @@ openspec-pw uninstall # Remove integration from the project
|
|
|
77
77
|
## Prerequisites
|
|
78
78
|
|
|
79
79
|
1. **Node.js >= 20**
|
|
80
|
-
2. **
|
|
81
|
-
3. **
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
claude mcp add playwright npx @playwright/mcp@latest
|
|
86
|
-
```
|
|
80
|
+
2. **Claude Code** with `.claude/` directory
|
|
81
|
+
3. **gstack** (for exploration + browser QA): `git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`
|
|
82
|
+
4. **OpenSpec** initialized: `npm install -g @fission-ai/openspec && openspec init`
|
|
83
|
+
5. **Playwright MCP** (for test execution + Healer): `claude mcp add playwright npx @playwright/mcp@latest`
|
|
87
84
|
|
|
88
85
|
## What `openspec-pw init` Does
|
|
89
86
|
|
|
@@ -101,14 +98,15 @@ Run through these steps in order when using the E2E workflow for the first time:
|
|
|
101
98
|
| Step | Command | If it fails |
|
|
102
99
|
|------|---------|-------------|
|
|
103
100
|
| 1. Install CLI | `npm install -g openspec-playwright` | Check Node.js version `node -v` (needs >= 20) |
|
|
104
|
-
| 2. Install
|
|
105
|
-
| 3.
|
|
106
|
-
| 4.
|
|
107
|
-
| 5. Install
|
|
108
|
-
| 6.
|
|
109
|
-
| 7.
|
|
110
|
-
| 8.
|
|
111
|
-
| 9.
|
|
101
|
+
| 2. Install gstack | `git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup` | Requires Bun: `curl -fsSL https://bun.sh/install | bash` |
|
|
102
|
+
| 3. Install OpenSpec | `npm install -g @fission-ai/openspec && openspec init` | `npm cache clean -f && npm install -g @fission-ai/openspec` |
|
|
103
|
+
| 4. Initialize E2E | `openspec-pw init` | Run `openspec-pw doctor` to see what's missing |
|
|
104
|
+
| 5. Install Playwright MCP | `claude mcp add playwright npx @playwright/mcp@latest` | `claude mcp list` to confirm installation |
|
|
105
|
+
| 6. Install browsers | `npx playwright install --with-deps` | macOS may need `xcode-select --install` first |
|
|
106
|
+
| 7. Start dev server | `npm run dev` (in a separate terminal) | Confirm port, set `BASE_URL` if non-standard |
|
|
107
|
+
| 8. Validate env | `npx playwright test tests/playwright/seed.spec.ts` | Check `webServer` in `playwright.config.ts` |
|
|
108
|
+
| 9. Configure auth (if needed) | See "Authentication" below | Debug with `npx playwright test --project=setup` |
|
|
109
|
+
| 10. Run first E2E | `/opsx:e2e <change-name>` | Check `openspec/reports/` for the report |
|
|
112
110
|
|
|
113
111
|
## Authentication
|
|
114
112
|
|
package/README.zh-CN.md
CHANGED
|
@@ -13,13 +13,10 @@ npm install -g openspec-playwright
|
|
|
13
13
|
## 前置条件
|
|
14
14
|
|
|
15
15
|
1. **Node.js >= 20**
|
|
16
|
-
2. **
|
|
17
|
-
3. **
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
claude mcp add playwright npx @playwright/mcp@latest
|
|
22
|
-
```
|
|
16
|
+
2. **Claude Code** 且项目中有 `.claude/` 目录
|
|
17
|
+
3. **gstack**(用于探索 + 浏览器 QA):`git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`
|
|
18
|
+
4. **OpenSpec** 已初始化: `npm install -g @fission-ai/openspec && openspec init`
|
|
19
|
+
5. **Playwright MCP**(用于测试执行 + Healer):`claude mcp add playwright npx @playwright/mcp@latest`
|
|
23
20
|
|
|
24
21
|
## 初始化
|
|
25
22
|
|
|
@@ -33,7 +30,7 @@ openspec-pw init # 安装 Playwright E2E 集成
|
|
|
33
30
|
|
|
34
31
|
## 支持的 AI 编码助手
|
|
35
32
|
|
|
36
|
-
Claude Code — E2E 工作流由 SKILL.md 驱动,使用 Playwright MCP
|
|
33
|
+
Claude Code — E2E 工作流由 SKILL.md 驱动,使用 /browse(探索)+ Playwright MCP(测试执行)。
|
|
37
34
|
|
|
38
35
|
## 使用
|
|
39
36
|
|
|
@@ -65,7 +62,7 @@ openspec-pw uninstall # 移除项目中的集成
|
|
|
65
62
|
│
|
|
66
63
|
├── 3. 验证环境 → 运行 seed.spec.ts
|
|
67
64
|
│
|
|
68
|
-
├── 4. 探索应用 →
|
|
65
|
+
├── 4. 探索应用 → /browse 探索真实 DOM
|
|
69
66
|
│ ├─ 读取 app-knowledge.md(项目级知识)
|
|
70
67
|
│ ├─ 从 specs 提取路由
|
|
71
68
|
│ ├─ 遍历每个路由 → snapshot → screenshot
|
|
@@ -102,14 +99,15 @@ openspec-pw uninstall # 移除项目中的集成
|
|
|
102
99
|
| 步骤 | 命令 | 失败时快速修复 |
|
|
103
100
|
|------|------|----------------|
|
|
104
101
|
| 1. 安装 CLI | `npm install -g openspec-playwright` | 检查 Node.js 版本 `node -v`(需 >= 20) |
|
|
105
|
-
| 2. 安装
|
|
106
|
-
| 3.
|
|
107
|
-
| 4.
|
|
108
|
-
| 5.
|
|
109
|
-
| 6.
|
|
110
|
-
| 7.
|
|
111
|
-
| 8.
|
|
112
|
-
| 9.
|
|
102
|
+
| 2. 安装 gstack | `git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup` | 需要 Bun:`curl -fsSL https://bun.sh/install \| bash` |
|
|
103
|
+
| 3. 安装 OpenSpec | `npm install -g @fission-ai/openspec && openspec init` | `npm cache clean -f && npm install -g @fission-ai/openspec` |
|
|
104
|
+
| 4. 初始化 E2E | `openspec-pw init` | 运行 `openspec-pw doctor` 查看具体缺失项 |
|
|
105
|
+
| 5. 安装 Playwright MCP | `claude mcp add playwright npx @playwright/mcp@latest` | `claude mcp list` 确认安装成功 |
|
|
106
|
+
| 6. 安装浏览器 | `npx playwright install --with-deps` | macOS 可能需先运行 `xcode-select --install` |
|
|
107
|
+
| 7. 启动开发服务器 | `npm run dev`(在另一个终端) | 确认端口,配置 `BASE_URL` |
|
|
108
|
+
| 8. 验证环境 | `npx playwright test tests/playwright/seed.spec.ts` | 检查 `playwright.config.ts` 中的 `webServer` 配置 |
|
|
109
|
+
| 9. 配置认证(如需要) | 见下方"认证配置" | `npx playwright test --project=setup` 调试 |
|
|
110
|
+
| 10. 运行第一个 E2E | `/opsx:e2e <change-name>` | 查看 `openspec/reports/` 中的报告 |
|
|
113
111
|
|
|
114
112
|
## 认证配置
|
|
115
113
|
|
package/employee-standards.md
CHANGED
|
@@ -1,50 +1,111 @@
|
|
|
1
|
-
# Claude Code Employee-Grade Configuration
|
|
1
|
+
# Claude Code Employee-Grade Configuration + gstack + openspec-playwright 生产闭环
|
|
2
2
|
|
|
3
3
|
> 员工级行为规范,适用于 OpenSpec 项目。
|
|
4
|
-
>
|
|
4
|
+
> 严格遵循 OpenSpec 规范驱动开发 + gstack 角色化虚拟工程团队 + Playwright 自动 E2E 验证。
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 0. 适用范围
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
本规范适用于 OpenSpec + openspec-playwright 项目(Claude Code 作为开发工具)。
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
E2E 工作流前提(由用户确保,非 AI 操作):
|
|
13
|
+
- gstack:`git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`(提供 `/browse` 探索 + `/qa` 浏览器验证)
|
|
14
|
+
- OpenSpec CLI:`npm install -g @fission-ai/openspec && openspec init`(提供变更管理能力)
|
|
15
|
+
- openspec-playwright:`openspec-pw init`(提供 `/opsx:e2e` 命令)
|
|
16
|
+
- Playwright MCP:`claude mcp add playwright npx @playwright/mcp@latest`(用于测试执行 + Healer)
|
|
17
|
+
- 浏览器已安装:`npx playwright install --with-deps`
|
|
18
|
+
- 项目包含 `specs/`、`changes/`、`tests/playwright/` 目录
|
|
13
19
|
|
|
14
|
-
|
|
20
|
+
## 1. 浏览器操作约束
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
所有浏览器操作用 gstack 的 `/browse` 探索 + `/qa` 验证,Playwright MCP 执行测试。Claude Code 会根据上下文自动调度,无需手动路由。
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
**冲突解决**:gstack 任何想直接修改代码的行为,都必须先确认当前 OpenSpec proposal 是否已存在并通过(检查 `changes/<name>/proposal.md` 是否处于 `approved` 状态)。
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
## 2. 代码质量(强制执行)
|
|
27
|
+
**lint + typecheck 后才能算成功**。动手前,先探索项目用什么工具:查看 `package.json` scripts、`Makefile`、`pyproject.toml`、`justfile` 等,找到该语言的 lint + typecheck 命令并执行。工具不存在时,明确告知用户,不得假装成功。
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
**拒绝"够用就行"**。架构缺陷、状态重复、模式不一致——必须说出来并修复。
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
**安全防护**:写 Go 时关注内存安全,写 Python 时关注反序列化,写 Web/API 时参考 OWASP Top 10 / OWASP API Top 10。先了解所用场景的风险模型。
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
## 3. 上下文管理
|
|
34
|
+
**文件读取完整**:超过 500 行的文件,不要假设单次读取覆盖完整内容——根据需要分次读取或编辑前重新读取完整文件。超过 10 条消息后,编辑任何文件前强制重新读取。
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
**OpenSpec 阶段隔离**:`specs/playwright/`、`tests/playwright/`(seed 除外)和 `test-plan.md` 由 `/opsx:e2e` 显式触发,不由 explore/propose/continue/apply/verify 等阶段自动推断。E2E 工作流是独立的。
|
|
29
37
|
|
|
38
|
+
**重构前清死代码**:未使用的 import/export/prop/console.log 先删掉,单独提交,再做重构。
|
|
39
|
+
|
|
40
|
+
## 4. 大规模任务处理
|
|
30
41
|
**子 Agent 并行化**:任务涉及超过 5 个独立文件时,启动并行子 agent(每个 5-8 个文件),每个拥有独立 token budget。
|
|
31
42
|
|
|
32
43
|
**分阶段执行**:每个阶段不超过 5 个文件,完成后验证,等待用户批准再继续。
|
|
33
44
|
|
|
34
|
-
**200 行以上修改必须走 OpenSpec**:代码改动超过 200 行时,禁止直接修改,必须通过 OpenSpec
|
|
45
|
+
**200 行以上修改必须走 OpenSpec**:代码改动超过 200 行时,禁止直接修改,必须通过 OpenSpec 工作流(/opsx:propose)。
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
## 5. 工具限制与编辑安全
|
|
48
|
+
**搜索要全**:重命名时,用 Grep 覆盖调用、类型、字符串、`import`、barrel file、测试 mock,不得假设一次覆盖所有情况。
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
**编辑要求**:编辑后重新读取文件确认变更正确应用。同一文件连续编辑不超过 3 次,中间必须重新读取。变更完成后,明确告知用户可能遗漏的区域(动态引用、测试 mock 等),提示人工复查。
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
**不主动推送**:除非用户明确要求,否则不推送代码。
|
|
53
|
+
|
|
54
|
+
**中文回复**:用中文回复用户。
|
|
41
55
|
|
|
42
56
|
---
|
|
43
57
|
|
|
44
|
-
##
|
|
58
|
+
## 6. 完整生产工作流(严格执行 + 反馈循环)
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
```
|
|
61
|
+
1. 探索与提案
|
|
62
|
+
2. 产品与架构评审(按需触发)
|
|
63
|
+
3. 设计审查
|
|
64
|
+
4. 实现 → /opsx:apply
|
|
65
|
+
5. 自审 → /opsx:verify /design-review /review
|
|
66
|
+
6. E2E 测试 → /opsx:e2e <change-name> → /browse 探索 + /qa 验证
|
|
67
|
+
7. 验证通过后归档 → /opsx:archive
|
|
68
|
+
8. 发布 → /ship 或 /land-and-deploy
|
|
69
|
+
9. 迭代回顾 → /retro
|
|
70
|
+
```
|
|
47
71
|
|
|
48
|
-
|
|
72
|
+
### 步骤详解
|
|
49
73
|
|
|
50
|
-
|
|
74
|
+
**1. 探索与提案**:现有项目先探索(`/opsx:explore`)再写 proposal(`/opsx:propose`);新项目(greenfield)直接生成 proposal + scenarios(记录到 `specs/` 和 `changes/`)。
|
|
75
|
+
|
|
76
|
+
**2. 产品与架构评审**(按需触发):
|
|
77
|
+
- `/office-hours`:产品方向、范围、优先级不确定时
|
|
78
|
+
- `/plan-ceo-review`:产品战略影响、竞争格局变化时
|
|
79
|
+
- `/plan-eng-review`:架构影响(新增服务、API 契约变更、数据模型重构)时
|
|
80
|
+
|
|
81
|
+
**3. 设计审查**:在实现前进行设计评审,确保方案合理。评审通过后开始实现。
|
|
82
|
+
|
|
83
|
+
**4. 实现**:执行 `/opsx:apply` 进行实现 → `lint + typecheck` 通过才算成功。
|
|
84
|
+
|
|
85
|
+
**5. 自审**:`/opsx:verify` `/design-review` `/review` 自审实现代码,确保质量。**设计审查后**,对 HTML/CSS 文件执行 CSS 结构审计(防止 `/design-review` 靠截图漏检间距问题):
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
两步式审计:
|
|
89
|
+
1. 确定间距基准 — 查 CSS variables / Tailwind spacing / Bootstrap $spacer
|
|
90
|
+
grep 'gap:|padding:|margin:' *.html → 提取值 → 对比基准,列低于基准的项
|
|
91
|
+
2. 检查 margin hack — 同一 grid/flex 容器中相邻元素各自用 margin 硬撑间距
|
|
92
|
+
信号:两个子元素的 margin 和 > 基准间距 2 倍 → 应改为 grid 行或 gap 控制
|
|
93
|
+
例:.desc{margin-b:36}+.btn{margin-t:80} 在同一 row → grid 行分离
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**6. E2E 测试生成与执行**:`/opsx:e2e <change-name>` 生成 Playwright 测试 → `/browse` 探索真实 DOM → Healer 自动修复 → `/qa` 真实浏览器验证。E2E 通过后进入发布环节。
|
|
97
|
+
|
|
98
|
+
**7. 验证通过后归档**:`/opsx:archive` 永久归档,更新 `specs/`
|
|
99
|
+
|
|
100
|
+
**8. 发布**:`/ship` 或 `/land-and-deploy`
|
|
101
|
+
|
|
102
|
+
**9. 迭代回顾**:`/retro`
|
|
103
|
+
|
|
104
|
+
### 反馈循环(生产中必然发生)
|
|
105
|
+
|
|
106
|
+
| 信号 | 回到 |
|
|
107
|
+
|------|------|
|
|
108
|
+
| 测试失败(App Bug) | 回到步骤 4 修复 → 重新测试 |
|
|
109
|
+
| 发现架构问题 | 回到步骤 2 重新评审 → 步骤 4 修复 |
|
|
110
|
+
| Proposal 需调整 | 回到步骤 1 重新提案 |
|
|
111
|
+
| 评审不通过 | 回到对应步骤重新处理 |
|
package/package.json
CHANGED
package/templates/test-plan.md
CHANGED
|
@@ -217,7 +217,7 @@ Bypass OTP UI entirely and test the protected endpoint directly.
|
|
|
217
217
|
|
|
218
218
|
**Test approach:**
|
|
219
219
|
```
|
|
220
|
-
1. Identify drag handle and drop target via
|
|
220
|
+
1. Identify drag handle and drop target via /browse snapshot
|
|
221
221
|
2. Use `page.dragAndDrop()` or `locator.dragTo()`
|
|
222
222
|
3. If custom implementation uses JS events, use `page.evaluate()` to dispatch events
|
|
223
223
|
4. Assert: target state reflects the drag result
|