openspec-playwright 0.2.7 → 0.2.9
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.
|
@@ -5,7 +5,7 @@ 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
6
|
metadata:
|
|
7
7
|
author: openspec-playwright
|
|
8
|
-
version: "2.
|
|
8
|
+
version: "2.22"
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Input
|
|
@@ -210,6 +210,32 @@ browser_navigate → browser_console_messages → browser_snapshot → browser_t
|
|
|
210
210
|
| Auth required, no credentials | Missing auth setup | Continue — skip protected routes, explore login page |
|
|
211
211
|
| Suspicious network request | API returned 4xx/5xx | Continue — mark `⚠️ API error: <endpoint> returned <code>` in app-exploration.md |
|
|
212
212
|
|
|
213
|
+
**Redirect / Refresh loop detection** — run after initial navigate:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
// 1. Initial capture
|
|
217
|
+
await browser_navigate(`${BASE_URL}/<route>`);
|
|
218
|
+
await new Promise(r => setTimeout(r, 1500)); // wait for SPA hydration
|
|
219
|
+
const url1 = await browser_evaluate(() => window.location.href);
|
|
220
|
+
|
|
221
|
+
// 2. Observe stability
|
|
222
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
223
|
+
const url2 = await browser_evaluate(() => window.location.href);
|
|
224
|
+
const msgs = await browser_console_messages();
|
|
225
|
+
|
|
226
|
+
// 3. Detect
|
|
227
|
+
if (url1 !== url2) {
|
|
228
|
+
→ ❌ URL changed — redirect loop (ERR_TOO_MANY_REDIRECTS)
|
|
229
|
+
→ Is this route protected without valid auth.storageState?
|
|
230
|
+
→ Yes → auth.setup.ts is broken → fix auth first
|
|
231
|
+
→ No → App middleware bug → mark route ❌ skip, record as App Bug
|
|
232
|
+
}
|
|
233
|
+
if (msgs.filter(m => m.type === 'warning' || m.type === 'error').length > 10) {
|
|
234
|
+
→ ❌ Excessive console errors — page refresh / JS crash loop
|
|
235
|
+
→ Mark route ❌ skip, record as App Bug
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
213
239
|
**Network monitoring**: After navigating, use `browser_network_requests` 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.
|
|
214
240
|
|
|
215
241
|
**For guest routes** (no auth):
|
|
@@ -323,7 +349,7 @@ After writing `app-exploration.md`, extract **project-level shared knowledge** a
|
|
|
323
349
|
| Common Selector Patterns | New patterns discovered that apply across routes |
|
|
324
350
|
| SPA Routing | SPA framework, routing behavior |
|
|
325
351
|
| Project Conventions | BASE_URL, auth method, multi-user roles |
|
|
326
|
-
| Selector Fixes | Healed selectors (see Step 9) — route, old
|
|
352
|
+
| Selector Fixes | Healed selectors (see Step 9) — route, old → new selector, reason, date |
|
|
327
353
|
|
|
328
354
|
Append only new/changed items — preserve existing content.
|
|
329
355
|
|
|
@@ -634,6 +660,10 @@ If tests fail → use Playwright MCP tools to inspect UI, fix selectors, re-run.
|
|
|
634
660
|
| `browser_take_screenshot` | Visually compare before/after fixes |
|
|
635
661
|
| `browser_run_code` | Execute custom fix logic (optional) |
|
|
636
662
|
|
|
663
|
+
**Before Phase 1 — check accumulated knowledge:**
|
|
664
|
+
|
|
665
|
+
Read `tests/playwright/app-knowledge.md` → **Selector Fixes** table. If the failing test's selector or route matches a known fix, use it directly (skip Phase 2). If partial match → use as the top candidate in Phase 2 Step 5a. If file does not exist → skip.
|
|
666
|
+
|
|
637
667
|
**Healer — Phase 1: Triage**
|
|
638
668
|
|
|
639
669
|
When a test fails, classify before attempting repair.
|
|
@@ -665,6 +695,8 @@ Proceed with individual Triage only for tests NOT in a batch failure group.
|
|
|
665
695
|
| **Network/Backend** | `net::ERR`, 4xx/5xx in console/network | **App Bug** | `test.skip()` + record in `app-bug-registry.md` |
|
|
666
696
|
| **JS Runtime Error** | Console error (non-network) | **App Bug** | `test.skip()` + record in `app-bug-registry.md` |
|
|
667
697
|
| **Auth Expired** | Redirected to login mid-test | **Flaky** | Re-run auth.setup → re-run |
|
|
698
|
+
| **Redirect Loop** | `ERR_TOO_MANY_REDIRECTS`, URL keeps changing on each snapshot | **App Bug** | Check auth first (see Step 4.2 loop detection). If auth is the cause → re-run auth. Otherwise → `test.skip()` + App Bug Registry |
|
|
699
|
+
| **Page Refresh Loop** | Excessive console errors (>10) after navigation, page unstable | **App Bug** | `test.skip()` + record in App Bug Registry |
|
|
668
700
|
| **Selector Not Found** | Element not found | **Test Bug** | → Phase 2 Healer |
|
|
669
701
|
| **Assertion Mismatch** | Wrong content/value | **Ambiguous** | → Phase 2 Healer |
|
|
670
702
|
| **Timeout** | waitFor/evaluate timeout | **Flaky** | Retry isolated: `openspec-pw run <name> --grep "<test-name>"` (1×, not counted in heal attempts). If it passes isolated but fails in suite → **RAFT**. If it consistently times out → check framework: React 19 / Next.js App Router: add `page.waitForLoadState('networkidle')`. Vue/Angular/React 18 / Plain JS / jQuery: use `waitForSelector(targetElement)` instead of timeout tuning. |
|
|
@@ -733,9 +765,29 @@ After Triage classifies failure as "Test Bug" or "Ambiguous":
|
|
|
733
765
|
- Data values differ (e.g., expected "¥1000" but got "¥999" → **Phase 3**, could be rounding, discount, or calculation bug)
|
|
734
766
|
- Missing elements after interaction (e.g., "after creating order, success message should appear" → no message → **Phase 3**)
|
|
735
767
|
|
|
736
|
-
5. If selector issue →
|
|
768
|
+
5. If selector issue → generate candidate list, then select:
|
|
769
|
+
|
|
770
|
+
**5a. Extract candidates** — identify the target element from the failing test's assertion, then from the snapshot list all selectors for that element:
|
|
771
|
+
|
|
772
|
+
First check `app-knowledge.md` → **Common Selector Patterns** for project-specific conventions (e.g., if project uses Tailwind and `.btn-primary` is listed as preferred → treat it as Fair or higher, not Fragile).
|
|
773
|
+
|
|
774
|
+
```
|
|
775
|
+
Target: <element from failing assertion, e.g. "button with text 'Submit'">
|
|
776
|
+
Candidates (stable → fragile):
|
|
777
|
+
- getByRole(button, { name: 'Submit' }) ← Stable (semantic)
|
|
778
|
+
- getByText('Submit') ← Fair (unique text)
|
|
779
|
+
- getByLabel('Email') ← Fair (form fields)
|
|
780
|
+
- locator('#submit') ← Fair (id attribute)
|
|
781
|
+
- locator('.btn-primary') ← Fragile (style class) — upgrade if listed in Common Selector Patterns
|
|
782
|
+
- locator('button:nth-child(3)') ← Fragile (DOM order)
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
Stability: `getByRole` > `getByText`/`getByLabel` > `locator('#id')` > `locator('.class')` > `locator('nth-child')`. Upgrade stability if `app-knowledge.md` → **Common Selector Patterns** explicitly lists the selector as preferred for this project.
|
|
786
|
+
|
|
787
|
+
**5b. Select top candidate** — pick the highest-stability candidate that matches the target. Output: `SELECTED: <selector> — reason: <why this one>`.
|
|
788
|
+
|
|
737
789
|
6. Apply fix → re-run **only that test** (attempt 1/3)
|
|
738
|
-
7. If healed → append to `app-knowledge.md` → **Selector Fixes** table (route, old → new selector, reason)
|
|
790
|
+
7. If healed → append to `app-knowledge.md` → **Selector Fixes** table (route, old → new selector, reason, date)
|
|
739
791
|
|
|
740
792
|
**Element Missing handling (when browser_snapshot shows element not found):**
|
|
741
793
|
|
|
@@ -844,7 +896,7 @@ Report template: `.claude/skills/openspec-e2e/templates/report.md`
|
|
|
844
896
|
| ------- | ------- |
|
|
845
897
|
| No specs / app-exploration.md missing (change mode) | **STOP** |
|
|
846
898
|
| JS errors or HTTP 5xx during exploration | **STOP** → user fixes app → re-run `/opsx:e2e <name>` to re-explore from Step 4 |
|
|
847
|
-
|
|
|
899
|
+
| Redirect loop / page refresh loop during exploration | **App Bug** — **STOP** → check auth.setup.ts first (common cause). If auth is valid → app middleware/cookie bug → mark route skipped, record in App Bug Registry. Re-run exploration after fix. |
|
|
848
900
|
| File already exists (app-exploration, test-plan, app-all.spec.ts, Page Objects) | Read and use — never regenerate |
|
|
849
901
|
| Test fails (network/backend) | **App Bug** — `test.skip()` + record in `app-bug-registry.md` |
|
|
850
902
|
| Test fails (selector/assertion) | **Test Bug/Ambiguous** — Healer Phase 1→2 (≤3 attempts) |
|