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.
@@ -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.7"
8
+ version: "2.8"
11
9
  ---
12
10
 
13
11
  ## Input
@@ -25,13 +23,9 @@ metadata:
25
23
 
26
24
  ## Architecture
27
25
 
28
- This skill implements the Playwright Test Agents pipeline:
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`). 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).
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. Mark as **auth required** only when BOTH conditions are met:
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
- Before generating tests, verify the environment is ready by running the seed test:
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
- **What this validates**:
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 passes or no auth required**: Proceed to Step 4.
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` by:
92
- - Listing each functional requirement as a test case
93
- - Marking each with `@role(user|admin|guest|none)` and `@auth(required|none)`
94
- - Including happy path AND key error paths
95
- - Referencing the route/page each test targets
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 unless user explicitly asks.
85
+ **Idempotency**: If test-plan.md already exists β†’ read it, use it, do NOT regenerate.
98
86
 
99
- ### 5. Generate test file (LLM-driven)
87
+ ### 5. Generate test file
100
88
 
101
- Use your file writing capability to create `tests/playwright/<name>.spec.ts`.
89
+ Create `tests/playwright/<name>.spec.ts`:
102
90
 
103
91
  **Read inputs first**:
104
- - `openspec/changes/<name>/specs/playwright/test-plan.md` β€” test cases with `@role` and `@auth` tags
105
- - `tests/playwright/seed.spec.ts` β€” code pattern, BASE_URL, and page object structure
106
-
107
- **Generate Playwright code** for each test case from test-plan.md:
108
- - Follow the same structure as `seed.spec.ts`
109
- - Prefer `data-testid` selectors; fallback to `input[name="..."]` or semantic selectors
110
- - Include **happy path** AND **error/edge cases**
111
- - Use `test.describe(...)` for grouping related tests
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
- ### Anti-Pattern Warnings (Generator)
102
+ #### Anti-Pattern Warnings
116
103
 
117
- **🚫 NEVER do this β€” False Pass pattern:**
104
+ **🚫 False Pass** β€” never silently skip when element is missing:
118
105
  ```typescript
119
- // WRONG: If button doesn't exist, test silently passes and tests nothing
120
- const btn = page.getByRole('button', { name: 'ε–ζΆˆ' }).first();
121
- if (await btn.isVisible().catch(() => false)) {
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
- **Why it matters**: A test that passes but skipped its logic gives **false confidence**. It reports green but tests nothing. Worse β€” if the test modifies data, a skipped run can corrupt state for the next test.
132
-
133
- **🚫 NEVER rely on Playwright projects for permission filtering:**
112
+ **🚫 Permission filtering** β€” use `@tag` with `--grep`, not projects:
134
113
  ```typescript
135
- // WRONG: All tests run under both admin AND user projects β€” false "16 tests" impression
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
- **🚫 NEVER skip auth guard tests:**
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 freshContext = await browser.newContext(); // No session cookies
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
- **Write the file** using the Write tool. If the file already exists β†’ diff against test-plan, add only missing test cases, preserve existing implementations.
127
+ **Always include error path tests** β€” API 500, 404, network timeout, invalid input.
186
128
 
187
- **Selector guidance**: If no `data-testid` exists in the app, prefer `getByRole`, `getByLabel`, `getByText` over fragile selectors like CSS paths.
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
- If auth is required:
192
-
193
- **API login**: If specs mention `/api/auth/login` or similar β†’ generate `tests/playwright/auth.setup.ts` using API login with `E2E_USERNAME`/`E2E_PASSWORD`.
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
- **UI login**: Otherwise β†’ generate `tests/playwright/auth.setup.ts` using UI login. Update selectors to match the login page (look for `data-testid` attributes or fallback to `input[name="..."]`).
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 credentials:
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. Then re-run /opsx:e2e to execute tests
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 (non-destructive)
148
+ ### 7. Configure playwright.config.ts
212
149
 
213
- If `playwright.config.ts` does not exist β†’ generate it from the schema template at `openspec/schemas/playwright-e2e/templates/playwright.config.ts`. The template auto-detects:
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 `playwright.config.ts` exists β†’ READ it first. Extract existing `webServer`, `use.baseURL`, and `projects`. Preserve ALL existing fields. Add `webServer` block if missing. Do NOT replace existing config values.
152
+ If exists β†’ READ first, preserve ALL existing fields, add only missing `webServer` block.
218
153
 
219
- ### 8. Execute tests via CLI
154
+ ### 8. Execute tests
220
155
 
221
156
  ```bash
222
157
  openspec-pw run <name> --project=<role>
223
158
  ```
224
159
 
225
- **For role-based tests using `@tag`** (recommended over `--project` filtering):
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 β†’ analyze failures, use **Playwright MCP tools** to inspect UI state, fix selectors in the test file, and re-run.
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 by checking error message and console output
251
- 2. Classify the failure:
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, timeout | `browser_console_messages` β†’ add `test.skip()` + report "backend error" |
256
- | **Selector changed** | Element not found, page loaded | `browser_snapshot` β†’ fix selector β†’ re-run |
257
- | **Assertion mismatch** | Element exists, wrong content/value | `browser_snapshot` β†’ compare β†’ fix assertion β†’ re-run |
258
- | **Timing issue** | `waitFor` timeout, race condition | Adjust wait strategy β†’ re-run |
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
- **Evidence checklist** (in order, stop at first match):
267
- | Check | Signal | Decision |
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 **after** the test suite completes (even if all tests pass). Scan for silent skips that give false confidence:
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
- **Indicator B β€” Test ran too fast:**
290
- A test covering a complex flow that completes in < 200ms is suspicious.
291
- β†’ Inspect with `browser_snapshot` to confirm page state
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
- **Indicator C β€” Auth guard not tested:**
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 the report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`.
304
-
305
- **Present results to user**:
306
- - Summary table (tests run, passed, failed, duration, final status)
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** (if all tests pass):
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
- ## Output Format
208
+ ## Report Structure
317
209
 
318
- ### Report Structure (`openspec/reports/playwright-e2e-<name>-<timestamp>.md`)
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 were detected. Review carefully.
237
+ > Tests passed but coverage gaps detected.
349
238
 
350
239
  | Test | Gap | Recommendation |
351
240
  |------|-----|----------------|
352
- | ... | Conditional visibility check β€” test may have skipped | file:line β€” use `expect().toBeVisible()` |
353
- | ... | Auth guard uses inherited session | Add fresh context test: `browser.newContext()` |
354
- | ... | Suspiciously fast execution (<200ms) | Verify test logic was actually executed |
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 found | Stop with info message β€” E2E requires specs |
366
- | Seed test fails | Stop with failure β€” fix environment before proceeding |
367
- | No auth required | Skip auth setup entirely |
368
- | test-plan.md exists | Read and use it β€” never regenerate |
369
- | auth.setup.ts exists | Verify format β€” update only if stale |
370
- | playwright.config.ts exists | Read and preserve all fields β€” add only missing |
371
- | Test fails (network/backend) | Skip with `test.skip()` β€” backend/app error, not test fragility |
372
- | Test fails (selector) | Healer: snapshot β†’ fix selector β†’ re-run (≀3 attempts) |
373
- | Test fails (assertion) | Healer: snapshot β†’ fix assertion β†’ re-run (≀3 attempts) |
374
- | 3 heal attempts failed | Confirm root cause β†’ if app bug: `test.skip()` + report; if unclear: report with recommendation |
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 TODO comments. Every test case in test-plan.md must produce an actual `test(...)` block.
391
- - Do NOT overwrite files outside: `specs/playwright/`, `tests/playwright/`, `openspec/reports/`, `playwright.config.ts`, `tests/auth.setup.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 };
@@ -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.41",
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
- - fix: correct escapeYamlValue usage for all 24 editor adapters
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.41
5
+ **Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.43
@@ -570,4 +570,4 @@ export function installSkill(projectRoot: string, skillContent: string): void {
570
570
  console.log(chalk.green(` βœ“ claude: .claude/skills/openspec-e2e/SKILL.md`));
571
571
  }
572
572
 
573
- export { claudeAdapter };
573
+ export { claudeAdapter, ALL_ADAPTERS };
@@ -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
- console.warn('⚠ E2E_USERNAME or E2E_PASSWORD not set β€” skipping API auth');
29
- return;
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
- console.warn('⚠ E2E_USERNAME or E2E_PASSWORD not set β€” skipping UI auth');
53
- return;
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: test@example.com
25
- password: testpassword123
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@example.com
30
- # password: adminpassword123
29
+ # username: CHANGE_ME@admin.com
30
+ # password: CHANGE_ME_ADMIN_PASSWORD
31
31
  # - name: premium
32
- # username: premium@example.com
33
- # password: premiumpassword123
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
+ });
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['tests/**/*.test.ts'],
6
+ globals: true,
7
+ environment: 'node',
8
+ },
9
+ });
Binary file