openspec-playwright 0.1.41 β 0.1.43
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 +83 -208
- package/dist/commands/editors.d.ts +2 -1
- package/dist/commands/editors.js +1 -1
- package/dist/commands/editors.js.map +1 -1
- package/openspec-playwright-0.1.43.tgz +0 -0
- package/package.json +5 -2
- package/release-notes.md +2 -2
- package/src/commands/editors.ts +1 -1
- package/templates/auth.setup.ts +17 -4
- package/templates/credentials.yaml +6 -6
- package/tests/editors.test.ts +180 -0
- package/vitest.config.ts +9 -0
- package/openspec-playwright-0.1.41.tgz +0 -0
|
@@ -3,11 +3,9 @@ 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
5
|
compatibility: Requires openspec CLI, Playwright (with browsers installed), and @playwright/mcp (globally installed via `claude mcp add playwright npx @playwright/mcp@latest`).
|
|
6
|
-
|
|
7
|
-
**Architecture**: Uses CLI + SKILLs (not `init-agents`). This follows Playwright's recommended approach for coding agents β CLI is more token-efficient than loading MCP tool schemas into context. MCP is used only for Healer (UI inspection on failure).
|
|
8
6
|
metadata:
|
|
9
7
|
author: openspec-playwright
|
|
10
|
-
version: "2.
|
|
8
|
+
version: "2.8"
|
|
11
9
|
---
|
|
12
10
|
|
|
13
11
|
## Input
|
|
@@ -25,13 +23,9 @@ metadata:
|
|
|
25
23
|
|
|
26
24
|
## Architecture
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- **π Planner** (Step 4): Consumes OpenSpec specs (`specs/*.md`) and produces `test-plan.md` β combines OpenSpec's structured requirements with LLMηΌζ.
|
|
31
|
-
- **π Generator** (Step 5): Transforms the Markdown test-plan into real Playwright `.spec.ts` files using LLM code generation.
|
|
32
|
-
- **π Healer** (Step 8): Executes the test suite and automatically repairs failing selectors via Playwright MCP tools.
|
|
26
|
+
Pipeline: **Planner** (Step 4) β **Generator** (Step 5) β **Healer** (Step 8).
|
|
33
27
|
|
|
34
|
-
Uses CLI + SKILLs (not `init-agents`).
|
|
28
|
+
Uses CLI + SKILLs (not `init-agents`). CLI is ~4x more token-efficient than loading MCP tool schemas. MCP is used only for Healer (UI inspection on failure).
|
|
35
29
|
|
|
36
30
|
**Schema owns templates. CLI handles execution. Skill handles cognitive work.**
|
|
37
31
|
|
|
@@ -56,7 +50,7 @@ If `openspec/changes/<name>/specs/` is empty, inform the user and stop. E2E requ
|
|
|
56
50
|
|
|
57
51
|
Read all files from `openspec/changes/<name>/specs/*.md`. Extract functional requirements.
|
|
58
52
|
|
|
59
|
-
Detect if auth is required
|
|
53
|
+
Detect if auth is required only when BOTH conditions are met:
|
|
60
54
|
|
|
61
55
|
**Condition A β Explicit markers**: "login", "signin", "logout", "authenticate", "protected", "authenticated", "session", "unauthorized"
|
|
62
56
|
|
|
@@ -71,169 +65,101 @@ Detect if auth is required. Mark as **auth required** only when BOTH conditions
|
|
|
71
65
|
|
|
72
66
|
### 3. Validate environment
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
Run the seed test before generating tests:
|
|
76
69
|
```bash
|
|
77
70
|
npx playwright test tests/playwright/seed.spec.ts --project=chromium
|
|
78
71
|
```
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
- App server is reachable (BASE_URL accessible)
|
|
82
|
-
- Auth fixtures (`storageState`) are initialized if auth is required
|
|
83
|
-
- Playwright browser and config are working
|
|
84
|
-
|
|
85
|
-
**If seed test fails**: Stop and report the failure. User must fix the environment before proceeding.
|
|
73
|
+
This validates: app server reachable, auth fixtures initialized, Playwright working.
|
|
86
74
|
|
|
87
|
-
**If seed test
|
|
75
|
+
**If seed test fails**: Stop and report. Fix the environment before proceeding.
|
|
88
76
|
|
|
89
77
|
### 4. Generate test plan
|
|
90
78
|
|
|
91
|
-
Create `openspec/changes/<name>/specs/playwright/test-plan.md
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
79
|
+
Create `openspec/changes/<name>/specs/playwright/test-plan.md`:
|
|
80
|
+
- List each functional requirement as a test case
|
|
81
|
+
- Mark with `@role(user|admin|guest|none)` and `@auth(required|none)`
|
|
82
|
+
- Include happy path AND error paths
|
|
83
|
+
- Reference the route/page each test targets
|
|
96
84
|
|
|
97
|
-
**Idempotency**: If test-plan.md already exists β read it, use it, do NOT regenerate
|
|
85
|
+
**Idempotency**: If test-plan.md already exists β read it, use it, do NOT regenerate.
|
|
98
86
|
|
|
99
|
-
### 5. Generate test file
|
|
87
|
+
### 5. Generate test file
|
|
100
88
|
|
|
101
|
-
|
|
89
|
+
Create `tests/playwright/<name>.spec.ts`:
|
|
102
90
|
|
|
103
91
|
**Read inputs first**:
|
|
104
|
-
- `openspec/changes/<name>/specs/playwright/test-plan.md`
|
|
105
|
-
- `tests/playwright/seed.spec.ts`
|
|
106
|
-
|
|
107
|
-
**Generate Playwright code
|
|
108
|
-
- Follow
|
|
109
|
-
- Prefer `data-testid
|
|
110
|
-
- Include
|
|
111
|
-
- Use `test.describe(...)` for grouping
|
|
92
|
+
- `openspec/changes/<name>/specs/playwright/test-plan.md`
|
|
93
|
+
- `tests/playwright/seed.spec.ts`
|
|
94
|
+
|
|
95
|
+
**Generate** Playwright code for each test case:
|
|
96
|
+
- Follow `seed.spec.ts` structure
|
|
97
|
+
- Prefer `data-testid`; fallback to `getByRole`, `getByLabel`, `getByText`
|
|
98
|
+
- Include happy path AND error/edge cases
|
|
99
|
+
- Use `test.describe(...)` for grouping
|
|
112
100
|
- Each test: `test('ζθΏ°ζ§εη§°', async ({ page }) => { ... })`
|
|
113
|
-
- Add `@project(user)` / `@project(admin)` on role-specific tests
|
|
114
101
|
|
|
115
|
-
|
|
102
|
+
#### Anti-Pattern Warnings
|
|
116
103
|
|
|
117
|
-
**π«
|
|
104
|
+
**π« False Pass** β never silently skip when element is missing:
|
|
118
105
|
```typescript
|
|
119
|
-
// WRONG
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
await btn.click();
|
|
123
|
-
await expect(page.getByText('ζε')).toBeVisible();
|
|
124
|
-
}
|
|
125
|
-
// β
CORRECT: Use assertion β test fails if element is missing
|
|
106
|
+
// WRONG
|
|
107
|
+
if (await btn.isVisible().catch(() => false)) { ... }
|
|
108
|
+
// β
CORRECT
|
|
126
109
|
await expect(page.getByRole('button', { name: 'εζΆ' })).toBeVisible();
|
|
127
|
-
await page.getByRole('button', { name: 'εζΆ' }).click();
|
|
128
|
-
await expect(page.getByText('ζε')).toBeVisible();
|
|
129
110
|
```
|
|
130
111
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
**π« NEVER rely on Playwright projects for permission filtering:**
|
|
112
|
+
**π« Permission filtering** β use `@tag` with `--grep`, not projects:
|
|
134
113
|
```typescript
|
|
135
|
-
|
|
136
|
-
projects: [{ name: 'admin' }, { name: 'user' }]
|
|
137
|
-
|
|
138
|
-
// β
CORRECT: Use @tag for permission-based test filtering
|
|
139
|
-
test('admin only - activate subscription', { tag: '@admin' }, async ({ page }) => { ... });
|
|
140
|
-
test('user only - view subscription', { tag: '@user' }, async ({ page }) => { ... });
|
|
114
|
+
test('admin only', { tag: '@admin' }, async ({ page }) => { ... });
|
|
141
115
|
// Run with: npx playwright test --grep "@admin"
|
|
142
116
|
```
|
|
143
117
|
|
|
144
|
-
**π«
|
|
145
|
-
The auth guard is a **critical security feature**. Skipping it leaves a gap in coverage.
|
|
118
|
+
**π« Auth guard** β test with FRESH browser context (no inherited cookies):
|
|
146
119
|
```typescript
|
|
147
|
-
// β
CORRECT: Test auth guard with a FRESH browser context (no cookies, no storage)
|
|
148
120
|
test('redirects unauthenticated user to login', async ({ browser }) => {
|
|
149
|
-
const
|
|
150
|
-
const freshPage = await freshContext.newPage();
|
|
121
|
+
const freshPage = await browser.newContext().newPage();
|
|
151
122
|
await freshPage.goto(`${BASE_URL}/dashboard`);
|
|
152
123
|
await expect(freshPage).toHaveURL(/login|auth/);
|
|
153
|
-
await freshContext.close();
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**Always include error path tests** (not just happy paths):
|
|
158
|
-
- API returns 500 β UI error message displayed?
|
|
159
|
-
- API returns 404 β graceful "not found" handling?
|
|
160
|
-
- Network timeout β retry or error UX?
|
|
161
|
-
- Invalid input β validation message shown?
|
|
162
|
-
|
|
163
|
-
**Example pattern** (from seed.spec.ts):
|
|
164
|
-
```typescript
|
|
165
|
-
import { test, expect } from '@playwright/test';
|
|
166
|
-
|
|
167
|
-
const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
|
|
168
|
-
|
|
169
|
-
test.describe('Feature Name', () => {
|
|
170
|
-
test('happy path - action succeeds', async ({ page }) => {
|
|
171
|
-
await page.goto(`${BASE_URL}/path`);
|
|
172
|
-
await page.getByTestId('element').click();
|
|
173
|
-
await expect(page.getByTestId('result')).toBeVisible();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test('error case - invalid input shows message', async ({ page }) => {
|
|
177
|
-
await page.goto(`${BASE_URL}/path`);
|
|
178
|
-
await page.getByTestId('input').fill('invalid');
|
|
179
|
-
await page.getByTestId('submit').click();
|
|
180
|
-
await expect(page.getByTestId('error')).toContainText('Error text');
|
|
181
|
-
});
|
|
182
124
|
});
|
|
183
125
|
```
|
|
184
126
|
|
|
185
|
-
**
|
|
127
|
+
**Always include error path tests** β API 500, 404, network timeout, invalid input.
|
|
186
128
|
|
|
187
|
-
|
|
129
|
+
If the file exists β diff against test-plan, add only missing test cases.
|
|
188
130
|
|
|
189
131
|
### 6. Configure auth (if required)
|
|
190
132
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
**
|
|
133
|
+
- **API login**: Generate `auth.setup.ts` using `E2E_USERNAME`/`E2E_PASSWORD` + POST to login endpoint
|
|
134
|
+
- **UI login**: Generate `auth.setup.ts` using browser form fill. Update selectors to match your login page
|
|
135
|
+
- **Multi-user**: Separate `storageState` paths per role
|
|
194
136
|
|
|
195
|
-
**
|
|
196
|
-
|
|
197
|
-
**Multi-user**: If specs mention multiple roles (admin + user) β generate separate `auth.setup.ts` blocks for each role with different `storageState` paths.
|
|
198
|
-
|
|
199
|
-
**Prompt user** with:
|
|
137
|
+
**Prompt user**:
|
|
200
138
|
```
|
|
201
|
-
Auth required. To set up
|
|
202
|
-
|
|
203
|
-
1. Customize tests/playwright/credentials.yaml with your test user
|
|
139
|
+
Auth required. To set up:
|
|
140
|
+
1. Customize tests/playwright/credentials.yaml
|
|
204
141
|
2. Export: export E2E_USERNAME=xxx E2E_PASSWORD=yyy
|
|
205
142
|
3. Run auth: npx playwright test --project=setup
|
|
206
|
-
4.
|
|
143
|
+
4. Re-run /opsx:e2e to execute tests
|
|
207
144
|
```
|
|
208
145
|
|
|
209
146
|
**Idempotency**: If `auth.setup.ts` already exists β verify format, update only if stale.
|
|
210
147
|
|
|
211
|
-
### 7. Configure playwright.config.ts
|
|
148
|
+
### 7. Configure playwright.config.ts
|
|
212
149
|
|
|
213
|
-
If
|
|
214
|
-
- **BASE_URL**: from `process.env.BASE_URL`, falling back to `tests/playwright/seed.spec.ts` β `BASE_URL` value, then `http://localhost:3000`
|
|
215
|
-
- **Dev command**: from `package.json` β scripts in order: `dev` β `start` β `serve` β `preview` β `npm run dev`
|
|
150
|
+
If missing β generate from `openspec/schemas/playwright-e2e/templates/playwright.config.ts`. Auto-detects BASE_URL and dev command from `package.json`.
|
|
216
151
|
|
|
217
|
-
If
|
|
152
|
+
If exists β READ first, preserve ALL existing fields, add only missing `webServer` block.
|
|
218
153
|
|
|
219
|
-
### 8. Execute tests
|
|
154
|
+
### 8. Execute tests
|
|
220
155
|
|
|
221
156
|
```bash
|
|
222
157
|
openspec-pw run <name> --project=<role>
|
|
223
158
|
```
|
|
224
159
|
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
npx playwright test tests/playwright/<name>.spec.ts --grep "@<role>"
|
|
228
|
-
```
|
|
229
|
-
The `--project` approach runs ALL tests under each project's credentials β use `@tag` with `--grep` for precise filtering.
|
|
230
|
-
|
|
231
|
-
The CLI handles:
|
|
232
|
-
- Server lifecycle (start β wait for HTTP β test β stop)
|
|
233
|
-
- Port mismatch detection
|
|
234
|
-
- Report generation at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`
|
|
160
|
+
The CLI handles: server lifecycle, port mismatch, report generation.
|
|
235
161
|
|
|
236
|
-
If tests fail β
|
|
162
|
+
If tests fail β use Playwright MCP tools to inspect UI, fix selectors, re-run.
|
|
237
163
|
|
|
238
164
|
**Healer MCP tools** (in order of use):
|
|
239
165
|
<!-- MCP_VERSION: 0.0.68 -->
|
|
@@ -247,77 +173,41 @@ If tests fail β analyze failures, use **Playwright MCP tools** to inspect UI s
|
|
|
247
173
|
| `browser_run_code` | Execute custom fix logic (optional) |
|
|
248
174
|
|
|
249
175
|
**Healer workflow**:
|
|
250
|
-
1. Read the failing test β identify failure type
|
|
251
|
-
2. Classify
|
|
176
|
+
1. Read the failing test β identify failure type
|
|
177
|
+
2. Classify:
|
|
252
178
|
|
|
253
179
|
| Failure type | Signal | Action |
|
|
254
180
|
|-------------|--------|--------|
|
|
255
|
-
| **Network/backend** | `fetch failed`, `net::ERR`, 5xx
|
|
256
|
-
| **Selector changed** | Element not found
|
|
257
|
-
| **Assertion mismatch** |
|
|
258
|
-
| **Timing issue** | `waitFor` timeout
|
|
259
|
-
|
|
260
|
-
3. **Attempt heal** (up to 3 times):
|
|
261
|
-
- Apply fix using `browser_snapshot` (prefer `getByRole`, `getByLabel`, `getByText`)
|
|
262
|
-
- Re-run: `openspec-pw run <name> --project=<role>`
|
|
263
|
-
|
|
264
|
-
4. **After 3 failed attempts**, collect evidence:
|
|
181
|
+
| **Network/backend** | `fetch failed`, `net::ERR`, 5xx | `browser_console_messages` β `test.skip()` |
|
|
182
|
+
| **Selector changed** | Element not found | `browser_snapshot` β fix selector β re-run |
|
|
183
|
+
| **Assertion mismatch** | Wrong content/value | `browser_snapshot` β fix assertion β re-run |
|
|
184
|
+
| **Timing issue** | `waitFor` timeout | Adjust wait strategy β re-run |
|
|
265
185
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|-------|--------|----------|
|
|
269
|
-
| `browser_console_messages` | ERROR-level messages present | App bug β `test.skip()` + report "console error" |
|
|
270
|
-
| `browser_snapshot` | Target element missing from DOM | App bug β `test.skip()` + report "element missing" |
|
|
271
|
-
| `browser_snapshot` | Element exists, no errors | Test bug β report recommendation |
|
|
272
|
-
|
|
273
|
-
- **App bug**: `test.skip('app bug β reason: <signal>')` + detailed report entry
|
|
274
|
-
- **Test bug**: report with "likely selector change, verify manually at file:line"
|
|
275
|
-
- Do NOT retry after evidence checklist β evidence is conclusive
|
|
186
|
+
3. **Attempt heal** (β€3 times): snapshot β fix β re-run
|
|
187
|
+
4. **After 3 failures**: collect evidence checklist β `test.skip()` if app bug, report recommendation if test bug
|
|
276
188
|
|
|
277
189
|
### 9. False Pass Detection
|
|
278
190
|
|
|
279
|
-
Run
|
|
280
|
-
|
|
281
|
-
**Indicator A β Conditional test logic:**
|
|
282
|
-
Look for patterns in the test file:
|
|
283
|
-
```typescript
|
|
284
|
-
if (await locator.isVisible().catch(() => false)) { ... }
|
|
285
|
-
```
|
|
286
|
-
β If test passes, the locator might not exist β check with `browser_snapshot`
|
|
287
|
-
β Report: "Test passed but may have skipped β conditional visibility check detected"
|
|
191
|
+
Run after test suite completes (even if all pass):
|
|
288
192
|
|
|
289
|
-
**
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
β Report: "Test duration suspiciously short β verify test logic was executed"
|
|
193
|
+
- **Conditional logic**: Look for `if (locator.isVisible().catch(() => false))` β if test passes, locator may not exist
|
|
194
|
+
- **Too fast**: < 200ms for a complex flow is suspicious
|
|
195
|
+
- **No fresh auth context**: Protected routes without `browser.newContext()`
|
|
293
196
|
|
|
294
|
-
|
|
295
|
-
If specs mention "protected route" or "redirect to login" but no test uses a fresh browser context:
|
|
296
|
-
β Report: "Auth guard not verified β test uses authenticated context (cookies/storage inherited)"
|
|
297
|
-
β Recommendation: Add a test with `browser.newContext()` (no storageState) to verify the guard
|
|
298
|
-
|
|
299
|
-
If any false-pass indicator is found β add a **β οΈ Coverage Gap** section to the report.
|
|
197
|
+
Report any gaps in a **β οΈ Coverage Gap** section.
|
|
300
198
|
|
|
301
199
|
### 10. Report results
|
|
302
200
|
|
|
303
|
-
Read
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
-
|
|
307
|
-
- Any auto-heal notes
|
|
308
|
-
- Recommendations for failed tests (with specific `file:line` references)
|
|
201
|
+
Read report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`. Present:
|
|
202
|
+
- Summary table (tests, passed, failed, duration, status)
|
|
203
|
+
- Auto-heal notes
|
|
204
|
+
- Recommendations with `file:line` references
|
|
309
205
|
|
|
310
|
-
**Update tasks.md**
|
|
311
|
-
- Read `openspec/changes/<name>/tasks.md`
|
|
312
|
-
- Find tasks related to E2E testing (look for `[ ]` items mentioning "test", "e2e", "playwright", "verify")
|
|
313
|
-
- Append a verification note: e.g. `β
Verified via Playwright E2E (<timestamp>)`
|
|
314
|
-
- Write the updated content back using the Edit tool
|
|
206
|
+
**Update tasks.md** if all tests pass: find E2E-related items, append `β
Verified via Playwright E2E (<timestamp>)`.
|
|
315
207
|
|
|
316
|
-
##
|
|
208
|
+
## Report Structure
|
|
317
209
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
```
|
|
210
|
+
```markdown
|
|
321
211
|
# Playwright E2E Report β <name>
|
|
322
212
|
|
|
323
213
|
## Summary
|
|
@@ -326,7 +216,6 @@ Read the report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`.
|
|
|
326
216
|
| N | N | N | Xm Xs | β
/β |
|
|
327
217
|
|
|
328
218
|
## Results
|
|
329
|
-
|
|
330
219
|
### Passed
|
|
331
220
|
| Test | Duration | Notes |
|
|
332
221
|
|------|----------|-------|
|
|
@@ -345,49 +234,35 @@ Read the report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`.
|
|
|
345
234
|
- [ ] Requirement 2 (unverified)
|
|
346
235
|
|
|
347
236
|
## β οΈ Coverage Gaps
|
|
348
|
-
> Tests passed but coverage gaps
|
|
237
|
+
> Tests passed but coverage gaps detected.
|
|
349
238
|
|
|
350
239
|
| Test | Gap | Recommendation |
|
|
351
240
|
|------|-----|----------------|
|
|
352
|
-
| ... | Conditional visibility check
|
|
353
|
-
| ... | Auth guard uses inherited session | Add fresh context test
|
|
354
|
-
| ... | Suspiciously fast execution (<200ms) | Verify test logic
|
|
355
|
-
|
|
356
|
-
### Updated tasks.md
|
|
357
|
-
```
|
|
358
|
-
- [x] Implement feature X β
Verified via Playwright E2E (2026-03-28)
|
|
241
|
+
| ... | Conditional visibility check | file:line β use `expect().toBeVisible()` |
|
|
242
|
+
| ... | Auth guard uses inherited session | Add fresh context test |
|
|
243
|
+
| ... | Suspiciously fast execution (<200ms) | Verify test logic executed |
|
|
359
244
|
```
|
|
360
245
|
|
|
361
246
|
## Graceful Degradation
|
|
362
247
|
|
|
363
248
|
| Scenario | Behavior |
|
|
364
249
|
|----------|----------|
|
|
365
|
-
| No specs
|
|
366
|
-
| Seed test fails | Stop
|
|
367
|
-
| No auth required | Skip auth setup
|
|
368
|
-
| test-plan.md exists | Read and use
|
|
369
|
-
| auth.setup.ts exists | Verify format
|
|
370
|
-
| playwright.config.ts exists |
|
|
371
|
-
| Test fails (
|
|
372
|
-
| Test fails (selector) | Healer: snapshot β fix
|
|
373
|
-
|
|
|
374
|
-
|
|
|
375
|
-
| False pass detected | Report coverage gap β add to "β οΈ Coverage Gap" section in report |
|
|
376
|
-
|
|
377
|
-
## Verification Heuristics
|
|
378
|
-
|
|
379
|
-
- **Coverage**: Every functional requirement β at least one test
|
|
380
|
-
- **Selector robustness**: Prefer `data-testid`, fallback to semantic selectors
|
|
381
|
-
- **False positives**: If test fails due to test bug (not app bug) β fix the test
|
|
382
|
-
- **Actionability**: Every failed test needs a specific recommendation
|
|
383
|
-
- **No false passes**: Every passing test must actually execute its test logic β verify absence of `if (isVisible())` conditional patterns
|
|
384
|
-
- **Auth guard verified**: Protected routes must have a test using a fresh browser context (no inherited cookies)
|
|
250
|
+
| No specs | Stop β E2E requires specs |
|
|
251
|
+
| Seed test fails | Stop β fix environment |
|
|
252
|
+
| No auth required | Skip auth setup |
|
|
253
|
+
| test-plan.md exists | Read and use (never regenerate) |
|
|
254
|
+
| auth.setup.ts exists | Verify format (update only if stale) |
|
|
255
|
+
| playwright.config.ts exists | Preserve all fields (add only missing) |
|
|
256
|
+
| Test fails (backend) | `test.skip()` + report |
|
|
257
|
+
| Test fails (selector/assertion) | Healer: snapshot β fix β re-run (β€3) |
|
|
258
|
+
| 3 heals failed | Evidence checklist β app bug: `test.skip()`; unclear: report |
|
|
259
|
+
| False pass detected | Add "β οΈ Coverage Gap" to report |
|
|
385
260
|
|
|
386
261
|
## Guardrails
|
|
387
262
|
|
|
388
263
|
- Read specs from `openspec/changes/<name>/specs/` as source of truth
|
|
389
264
|
- Do NOT generate tests that contradict the specs
|
|
390
|
-
- **DO generate real, runnable Playwright test code** β not placeholders or
|
|
391
|
-
- Do NOT overwrite files outside: `specs/playwright/`, `tests/playwright/`, `openspec/reports/`, `playwright.config.ts
|
|
265
|
+
- **DO generate real, runnable Playwright test code** β not placeholders or TODOs
|
|
266
|
+
- Do NOT overwrite files outside: `specs/playwright/`, `tests/playwright/`, `openspec/reports/`, `playwright.config.ts`
|
|
392
267
|
- Cap auto-heal at 3 attempts
|
|
393
268
|
- If no change specified β always ask user to select
|
|
@@ -20,6 +20,7 @@ export interface EditorAdapter {
|
|
|
20
20
|
}
|
|
21
21
|
/** Claude Code: .claude/commands/opsx/<id>.md + SKILL.md */
|
|
22
22
|
declare const claudeAdapter: EditorAdapter;
|
|
23
|
+
declare const ALL_ADAPTERS: EditorAdapter[];
|
|
23
24
|
/** Detect which editors are installed by checking their config directories */
|
|
24
25
|
export declare function detectEditors(projectRoot: string): EditorAdapter[];
|
|
25
26
|
/** Detect Codex by checking if CODEX_HOME or ~/.codex exists */
|
|
@@ -30,4 +31,4 @@ export declare function buildCommandMeta(body: string): CommandMeta;
|
|
|
30
31
|
export declare function installForAllEditors(body: string, adapters: EditorAdapter[], projectRoot: string): void;
|
|
31
32
|
/** Install SKILL.md only for Claude Code */
|
|
32
33
|
export declare function installSkill(projectRoot: string, skillContent: string): void;
|
|
33
|
-
export { claudeAdapter };
|
|
34
|
+
export { claudeAdapter, ALL_ADAPTERS };
|
package/dist/commands/editors.js
CHANGED
|
@@ -486,5 +486,5 @@ export function installSkill(projectRoot, skillContent) {
|
|
|
486
486
|
writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
|
|
487
487
|
console.log(chalk.green(` β claude: .claude/skills/openspec-e2e/SKILL.md`));
|
|
488
488
|
}
|
|
489
|
-
export { claudeAdapter };
|
|
489
|
+
export { claudeAdapter, ALL_ADAPTERS };
|
|
490
490
|
//# sourceMappingURL=editors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editors.js","sourceRoot":"","sources":["../../src/commands/editors.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editors.js","sourceRoot":"","sources":["../../src/commands/editors.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openspec-playwright",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"description": "OpenSpec + Playwright E2E verification setup tool for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"test:run": "vitest run",
|
|
11
13
|
"prepublishOnly": "npm run build",
|
|
12
14
|
"release": "npm version patch && npm run build && git push && git push --tags && npm publish"
|
|
13
15
|
},
|
|
@@ -18,7 +20,8 @@
|
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@types/node": "^22.0.0",
|
|
21
|
-
"typescript": "^5.6.0"
|
|
23
|
+
"typescript": "^5.6.0",
|
|
24
|
+
"vitest": "^4.1.2"
|
|
22
25
|
},
|
|
23
26
|
"engines": {
|
|
24
27
|
"node": ">=20"
|
package/release-notes.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## What's Changed
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- chore: regenerate package-lock.json with vitest dev dependency
|
|
4
4
|
|
|
5
|
-
**Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.
|
|
5
|
+
**Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.43
|
package/src/commands/editors.ts
CHANGED
package/templates/auth.setup.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// For multi-user testing, add more setup blocks with different storageState paths.
|
|
14
14
|
|
|
15
15
|
import { test as setup, expect } from '@playwright/test';
|
|
16
|
+
import { existsSync } from 'fs';
|
|
16
17
|
|
|
17
18
|
// βββ API Login (preferred) βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
18
19
|
// If your app has a login API, configure it in tests/playwright/credentials.yaml:
|
|
@@ -25,8 +26,10 @@ setup('authenticate via API', async ({ page }) => {
|
|
|
25
26
|
const password = process.env.E2E_PASSWORD;
|
|
26
27
|
|
|
27
28
|
if (!username || !password) {
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
throw new Error(
|
|
30
|
+
'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
|
|
31
|
+
'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
|
|
32
|
+
);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
const res = await page.request.post(`${baseUrl}/api/auth/login`, {
|
|
@@ -38,6 +41,10 @@ setup('authenticate via API', async ({ page }) => {
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
await page.context().storageState({ path: './playwright/.auth/user.json' });
|
|
44
|
+
|
|
45
|
+
if (!existsSync('./playwright/.auth/user.json')) {
|
|
46
|
+
throw new Error('Auth setup failed: storageState file was not created');
|
|
47
|
+
}
|
|
41
48
|
});
|
|
42
49
|
|
|
43
50
|
// βββ UI Login (fallback) βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -49,8 +56,10 @@ setup('authenticate via UI', async ({ page }) => {
|
|
|
49
56
|
const password = process.env.E2E_PASSWORD;
|
|
50
57
|
|
|
51
58
|
if (!username || !password) {
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
throw new Error(
|
|
60
|
+
'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
|
|
61
|
+
'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
|
|
62
|
+
);
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
// TODO: Update these selectors to match your login page
|
|
@@ -74,4 +83,8 @@ setup('authenticate via UI', async ({ page }) => {
|
|
|
74
83
|
await expect(page).not.toHaveURL(/.*login.*|.*signin.*/);
|
|
75
84
|
|
|
76
85
|
await page.context().storageState({ path: './playwright/.auth/user.json' });
|
|
86
|
+
|
|
87
|
+
if (!existsSync('./playwright/.auth/user.json')) {
|
|
88
|
+
throw new Error('Auth setup failed: storageState file was not created');
|
|
89
|
+
}
|
|
77
90
|
});
|
|
@@ -21,13 +21,13 @@ api: /api/auth/login # Leave empty for UI login
|
|
|
21
21
|
|
|
22
22
|
users:
|
|
23
23
|
- name: user
|
|
24
|
-
username:
|
|
25
|
-
password:
|
|
24
|
+
username: CHANGE_ME@example.com
|
|
25
|
+
password: CHANGE_ME_PASSWORD
|
|
26
26
|
|
|
27
27
|
# Multi-user example (uncomment and configure for role-based tests):
|
|
28
28
|
# - name: admin
|
|
29
|
-
# username: admin
|
|
30
|
-
# password:
|
|
29
|
+
# username: CHANGE_ME@admin.com
|
|
30
|
+
# password: CHANGE_ME_ADMIN_PASSWORD
|
|
31
31
|
# - name: premium
|
|
32
|
-
# username: premium
|
|
33
|
-
# password:
|
|
32
|
+
# username: CHANGE_ME@premium.com
|
|
33
|
+
# password: CHANGE_ME_PREMIUM_PASSWORD
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
escapeYamlValue,
|
|
4
|
+
formatTagsArray,
|
|
5
|
+
buildCommandMeta,
|
|
6
|
+
detectEditors,
|
|
7
|
+
detectCodex,
|
|
8
|
+
ALL_ADAPTERS,
|
|
9
|
+
} from '../src/commands/editors.js';
|
|
10
|
+
|
|
11
|
+
// βββ escapeYamlValue ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
12
|
+
|
|
13
|
+
describe('escapeYamlValue', () => {
|
|
14
|
+
it('returns raw value for plain strings', () => {
|
|
15
|
+
expect(escapeYamlValue('hello world')).toBe('hello world');
|
|
16
|
+
expect(escapeYamlValue('simple')).toBe('simple');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('quotes strings with colons', () => {
|
|
20
|
+
expect(escapeYamlValue('hello: world')).toBe('"hello: world"');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('quotes strings starting with whitespace', () => {
|
|
24
|
+
expect(escapeYamlValue(' hello')).toBe('" hello"');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('quotes strings ending with whitespace', () => {
|
|
28
|
+
expect(escapeYamlValue('hello ')).toBe('"hello "');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('quotes and escapes strings containing quotes', () => {
|
|
32
|
+
expect(escapeYamlValue('say "hello"')).toBe('"say \\"hello\\""');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('quotes and escapes strings containing newlines', () => {
|
|
36
|
+
expect(escapeYamlValue('line1\nline2')).toBe('"line1\\nline2"');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('quotes strings with special YAML chars', () => {
|
|
40
|
+
expect(escapeYamlValue('key: value')).toBe('"key: value"');
|
|
41
|
+
expect(escapeYamlValue('# comment')).toBe('"# comment"');
|
|
42
|
+
expect(escapeYamlValue('a{b}c')).toBe('"a{b}c"');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('quotes strings with array-like chars', () => {
|
|
46
|
+
expect(escapeYamlValue('[a, b]')).toBe('"[a, b]"');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// βββ formatTagsArray βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
51
|
+
|
|
52
|
+
describe('formatTagsArray', () => {
|
|
53
|
+
it('formats empty tags', () => {
|
|
54
|
+
expect(formatTagsArray([])).toBe('[]');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('formats single tag', () => {
|
|
58
|
+
expect(formatTagsArray(['openspec'])).toBe('[openspec]');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('formats multiple tags', () => {
|
|
62
|
+
expect(formatTagsArray(['openspec', 'playwright', 'e2e'])).toBe(
|
|
63
|
+
'[openspec, playwright, e2e]'
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('escapes tags with colons using YAML quoting', () => {
|
|
68
|
+
// escapeYamlValue quotes 'tag:colon' β "tag:colon", so array has quoted element
|
|
69
|
+
expect(formatTagsArray(['tag:colon'])).toBe('["tag:colon"]');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// βββ buildCommandMeta βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
74
|
+
|
|
75
|
+
describe('buildCommandMeta', () => {
|
|
76
|
+
it('creates meta with correct id', () => {
|
|
77
|
+
const meta = buildCommandMeta('test body');
|
|
78
|
+
expect(meta.id).toBe('e2e');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('creates meta with correct fields', () => {
|
|
82
|
+
const meta = buildCommandMeta('test body');
|
|
83
|
+
expect(meta.name).toBe('OPSX: E2E');
|
|
84
|
+
expect(meta.description).toBe('Run Playwright E2E verification for an OpenSpec change');
|
|
85
|
+
expect(meta.category).toBe('OpenSpec');
|
|
86
|
+
expect(meta.tags).toEqual(['openspec', 'playwright', 'e2e', 'testing']);
|
|
87
|
+
expect(meta.body).toBe('test body');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// βββ detectEditors ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
92
|
+
|
|
93
|
+
describe('detectEditors', () => {
|
|
94
|
+
it('returns empty array for non-existent directory', () => {
|
|
95
|
+
const result = detectEditors('/tmp/nonexistent-project-xyz-123');
|
|
96
|
+
expect(result).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('detects Claude Code when .claude directory exists', () => {
|
|
100
|
+
const result = detectEditors('/Users/wxhou/Documents/openspec-playwright');
|
|
101
|
+
const names = result.map(a => a.toolId);
|
|
102
|
+
expect(names).toContain('claude');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// βββ detectCodex βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
107
|
+
|
|
108
|
+
describe('detectCodex', () => {
|
|
109
|
+
it('returns null when CODEX_HOME is set to non-existent path', () => {
|
|
110
|
+
const original = process.env.CODEX_HOME;
|
|
111
|
+
process.env.CODEX_HOME = '/tmp/this-codex-dir-does-not-exist-xyz';
|
|
112
|
+
const result = detectCodex();
|
|
113
|
+
expect(result).toBeNull();
|
|
114
|
+
if (original !== undefined) {
|
|
115
|
+
process.env.CODEX_HOME = original;
|
|
116
|
+
} else {
|
|
117
|
+
delete process.env.CODEX_HOME;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// βββ Adapter format correctness βββββββββββββββββββββββββββββββββββββββββββββββ
|
|
123
|
+
|
|
124
|
+
describe('Adapter format correctness', () => {
|
|
125
|
+
it('every adapter has a toolId', () => {
|
|
126
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
127
|
+
expect(adapter.toolId).toBeTruthy();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('every adapter has formatCommand that returns non-empty string', () => {
|
|
132
|
+
const meta = buildCommandMeta('test body content');
|
|
133
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
134
|
+
const output = adapter.formatCommand(meta);
|
|
135
|
+
expect(output.length).toBeGreaterThan(0);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('every adapter getCommandPath returns a path with the id', () => {
|
|
140
|
+
const meta = buildCommandMeta('test');
|
|
141
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
142
|
+
const path = adapter.getCommandPath(meta.id);
|
|
143
|
+
expect(path).toContain('opsx');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('Claude adapter output has YAML frontmatter', () => {
|
|
148
|
+
const meta = buildCommandMeta('body');
|
|
149
|
+
const output = ALL_ADAPTERS[0].formatCommand(meta);
|
|
150
|
+
expect(output).toContain('---');
|
|
151
|
+
expect(output).toContain('name:');
|
|
152
|
+
expect(output).toContain('description:');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('TOML adapters (gemini, qwen) do not use YAML frontmatter', () => {
|
|
156
|
+
const meta = buildCommandMeta('body');
|
|
157
|
+
const adapters = ALL_ADAPTERS.filter(
|
|
158
|
+
a => a.toolId === 'gemini' || a.toolId === 'qwen'
|
|
159
|
+
);
|
|
160
|
+
for (const adapter of adapters) {
|
|
161
|
+
const output = adapter.formatCommand(meta);
|
|
162
|
+
expect(output).not.toContain('---');
|
|
163
|
+
expect(output).toContain('description =');
|
|
164
|
+
expect(output).toContain('prompt =');
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('crush and qoder use raw values without escaping in name/description', () => {
|
|
169
|
+
const meta = buildCommandMeta('body');
|
|
170
|
+
const adapters = ALL_ADAPTERS.filter(
|
|
171
|
+
a => a.toolId === 'crush' || a.toolId === 'qoder'
|
|
172
|
+
);
|
|
173
|
+
for (const adapter of adapters) {
|
|
174
|
+
const output = adapter.formatCommand(meta);
|
|
175
|
+
// Should NOT have escaped quotes in the raw-value fields
|
|
176
|
+
expect(output).not.toContain('\\\\"');
|
|
177
|
+
expect(output).toContain('name: OPSX: E2E');
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
package/vitest.config.ts
ADDED
|
Binary file
|