@sun-asterisk/sungen 2.3.1 → 2.4.1

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.
Files changed (105) hide show
  1. package/README.md +10 -11
  2. package/dist/cli/index.js +1 -1
  3. package/dist/generators/gherkin-parser/index.d.ts +8 -0
  4. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  5. package/dist/generators/gherkin-parser/index.js +12 -0
  6. package/dist/generators/gherkin-parser/index.js.map +1 -1
  7. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +1 -1
  8. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +5 -1
  9. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +15 -0
  10. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +7 -1
  11. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +5 -1
  12. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  13. package/dist/generators/test-generator/patterns/index.js +2 -1
  14. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  15. package/dist/generators/test-generator/patterns/table-patterns.d.ts +12 -0
  16. package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +1 -1
  17. package/dist/generators/test-generator/patterns/table-patterns.js +142 -98
  18. package/dist/generators/test-generator/patterns/table-patterns.js.map +1 -1
  19. package/dist/generators/test-generator/patterns/types.d.ts +2 -0
  20. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  21. package/dist/generators/test-generator/step-mapper.d.ts +13 -0
  22. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  23. package/dist/generators/test-generator/step-mapper.js +80 -0
  24. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  25. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  26. package/dist/orchestrator/ai-rules-updater.js +8 -6
  27. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  28. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  29. package/dist/orchestrator/project-initializer.js +33 -2
  30. package/dist/orchestrator/project-initializer.js.map +1 -1
  31. package/dist/orchestrator/screen-manager.js +1 -1
  32. package/dist/orchestrator/screen-manager.js.map +1 -1
  33. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +5 -5
  34. package/{src/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md → dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md} +7 -7
  35. package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +21 -0
  36. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +32 -0
  37. package/dist/orchestrator/templates/ai-instructions/claude-config.md +65 -12
  38. package/dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +128 -52
  39. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +15 -39
  40. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +72 -259
  41. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +57 -205
  42. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +104 -0
  43. package/dist/orchestrator/templates/ai-instructions/claude-skill-viewpoint.md +188 -0
  44. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +4 -4
  45. package/dist/orchestrator/templates/ai-instructions/{copilot-cmd-make-tc.md → copilot-cmd-create-test.md} +8 -8
  46. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +24 -0
  47. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +35 -0
  48. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +66 -13
  49. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +128 -52
  50. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +15 -39
  51. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +72 -234
  52. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +57 -205
  53. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +104 -0
  54. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint.md +188 -0
  55. package/dist/orchestrator/templates/readme.md +85 -22
  56. package/package.json +1 -1
  57. package/src/cli/index.ts +1 -1
  58. package/src/generators/gherkin-parser/index.ts +23 -0
  59. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +1 -1
  60. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +5 -1
  61. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +15 -0
  62. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +7 -1
  63. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +5 -1
  64. package/src/generators/test-generator/patterns/index.ts +2 -1
  65. package/src/generators/test-generator/patterns/table-patterns.ts +155 -111
  66. package/src/generators/test-generator/patterns/types.ts +2 -0
  67. package/src/generators/test-generator/step-mapper.ts +87 -1
  68. package/src/orchestrator/ai-rules-updater.ts +8 -6
  69. package/src/orchestrator/project-initializer.ts +38 -2
  70. package/src/orchestrator/screen-manager.ts +1 -1
  71. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +5 -5
  72. package/{dist/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md → src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md} +7 -7
  73. package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +21 -0
  74. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +32 -0
  75. package/src/orchestrator/templates/ai-instructions/claude-config.md +65 -12
  76. package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +128 -52
  77. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +15 -39
  78. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +72 -259
  79. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +57 -205
  80. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +104 -0
  81. package/src/orchestrator/templates/ai-instructions/claude-skill-viewpoint.md +188 -0
  82. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +4 -4
  83. package/src/orchestrator/templates/ai-instructions/{copilot-cmd-make-tc.md → copilot-cmd-create-test.md} +8 -8
  84. package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +24 -0
  85. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +35 -0
  86. package/src/orchestrator/templates/ai-instructions/copilot-config.md +66 -13
  87. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +128 -52
  88. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +15 -39
  89. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +72 -234
  90. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +57 -205
  91. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +104 -0
  92. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-viewpoint.md +188 -0
  93. package/src/orchestrator/templates/readme.md +85 -22
  94. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +0 -2
  95. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +0 -2
  96. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +0 -29
  97. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-review.md +0 -228
  98. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +0 -32
  99. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-review.md +0 -228
  100. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +0 -2
  101. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +0 -2
  102. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +0 -29
  103. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-review.md +0 -228
  104. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +0 -32
  105. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-review.md +0 -228
@@ -1,312 +1,125 @@
1
1
  ---
2
2
  name: sungen-selector-fix
3
- description: 'Selector generation and fixing strategy for make-test explores live page, generates selectors.yaml, auto-fixes on test failure. Auto-loaded by make-test command.'
3
+ description: 'Selector fixing strategy diagnose failures, explore live page targeted, fix broken selectors. Auto-loaded by run-test command.'
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
- ## Selector Generation & Fix Strategy
7
+ ## Strategy: Fix Only What Breaks
8
8
 
9
- ### When to Generate Selectors
9
+ Most selectors auto-infer from Gherkin element types (see `sungen-selector-keys` skill). Only add YAML entries for selectors that fail during test execution.
10
10
 
11
- Selectors are generated during `/sungen:make-test`, NOT during `/sungen:make-tc`. This ensures selectors are always validated against the live page.
11
+ **Minimal `selectors.yaml`**: page selectors (required), overrides for elements where auto-infer doesn't work. Never generate a full page catalog upfront.
12
12
 
13
13
  ---
14
14
 
15
- ### Step 1: Authenticate
15
+ ## Step 1: Diagnose Failures
16
16
 
17
- 1. Read `baseURL` from `playwright.config.ts`
18
- 2. `browser_navigate` to `baseURL`
19
- 3. If redirected to login, ask the user to log in manually:
20
- > "This page requires login. Please log in using the browser. Confirm when you're done."
21
- 4. Once confirmed, `browser_navigate` to the target page and take `browser_snapshot`
17
+ Parse Playwright error output to categorize failures:
22
18
 
23
- **Never use `sungen makeauth`.** Always let the user log in manually via the MCP browser.
24
- **Never use `browser_evaluate` to inject cookies or localStorage.** Use `browser_evaluate` only to read DOM info (e.g. detect `data-testid` attributes, check element properties).
19
+ | Error pattern | Root cause | Fix target |
20
+ |---|---|---|
21
+ | `No element found` / `strict mode violation` | Selector mismatch | `selectors.yaml` |
22
+ | `toBeVisible` timeout | Wrong name or missing element | `selectors.yaml` |
23
+ | `toHaveText` / `toHaveValue` mismatch | Wrong expected data | `test-data.yaml` |
24
+ | `page.goto` error | Wrong URL | page selector in `selectors.yaml` |
25
+ | `frame` error | Element inside iframe | add `frame` field |
25
26
 
26
- ---
27
+ **Group by root cause** — if 5 tests fail because `[Submit]` button has a different name, that's 1 fix, not 5.
27
28
 
28
- ### Step 2: Build an Element Catalog from the Snapshot
29
+ **Check `test-results/` first** Playwright captures failure screenshots automatically. Use these to diagnose before any MCP exploration.
29
30
 
30
- **Never guess or infer selector names from Gherkin labels. Always copy exact values from the snapshot.**
31
+ ---
31
32
 
32
- After taking the snapshot, mentally catalog ALL accessible elements:
33
+ ## Step 2: Targeted MCP Exploration
33
34
 
34
- - **Buttons**: list each `button "..."` with its exact accessible name
35
- - **Links**: list each `link "..."` with its exact accessible name
36
- - **Headings**: list each `heading "..."` with level and exact name
37
- - **Inputs**: list each `textbox`, `searchbox`, `combobox` — note if it has an accessible name or not
38
- - **Regions/landmarks**: `region "..."`, `navigation "..."`, `dialog "..."`
39
- - **Images**: `img "..."` with accessible name (alt text)
35
+ Only when `test-results/` screenshots are insufficient:
40
36
 
41
- Then check for `data-testid` attributes (more stable than accessible names):
42
- ```js
43
- // browser_evaluate read-only, safe:
44
- Array.from(document.querySelectorAll('[data-testid]'))
45
- .map(e => ({ testid: e.dataset.testid, tag: e.tagName, text: e.textContent.trim().slice(0, 60) }))
46
- ```
37
+ 1. Read `baseURL` from `playwright.config.ts`
38
+ 2. `browser_navigate` to target page
39
+ 3. If redirected to login → ask user to log in manually via MCP browser
40
+ 4. Take **ONE** `browser_snapshot` — fix all broken selectors from this single snapshot
41
+
42
+ **Never use `sungen makeauth`.** Never use `browser_evaluate` to inject cookies.
47
43
 
48
44
  ---
49
45
 
50
- ### Step 3: Map Gherkin Labels → Selectors
46
+ ## Step 3: Fix Broken Selectors
51
47
 
52
- For each `[Reference]` in the `.feature` file, find the best match in the element catalog.
48
+ For each failed selector, find the correct locator from the snapshot:
53
49
 
54
- #### Selector priority (use first applicable)
50
+ Selector priority (use first applicable):
55
51
 
56
- | Priority | type | When to use |
52
+ | Priority | type | When |
57
53
  |---|---|---|
58
- | 1 | `testid` | `data-testid` attribute exists |
59
- | 2 | `role` + exact name | Interactive elements (button, link, heading) |
60
- | 3 | `placeholder` | Input with visible placeholder text |
61
- | 4 | `label` | Form field with `<label>` association |
62
- | 5 | `locator` (CSS / aria attr) | No accessible name (e.g. bare searchbox, icon button) |
63
- | 6 | `text` | Static text only — avoid for dynamic/data-driven content |
64
-
65
- #### The exact name rule
54
+ | 1 | `testid` | `data-testid` exists |
55
+ | 2 | `role` + exact name | Interactive elements |
56
+ | 3 | `placeholder` | Input with placeholder |
57
+ | 4 | `label` | Form field with `<label>` |
58
+ | 5 | `locator` (CSS) | No accessible name |
59
+ | 6 | `text` | Static text only |
66
60
 
67
- Copy the accessible name **character-for-character** from the snapshot. Do not transform, translate, or infer from the Gherkin label.
61
+ **Exact name rule**: copy name character-for-character from snapshot. Never infer from Gherkin label.
68
62
 
69
- ```yaml
70
- # BAD — name inferred from Gherkin label, not from snapshot
71
- notification bell:
72
- type: 'role'
73
- value: 'button'
74
- name: 'Notification Bell'
75
-
76
- # GOOD — exact name from snapshot: button "Notifications"
77
- notification bell:
78
- type: 'role'
79
- value: 'button'
80
- name: 'Notifications'
63
+ Check for `data-testid` attributes if role-based matching fails:
64
+ ```js
65
+ Array.from(document.querySelectorAll('[data-testid]'))
66
+ .map(e => ({ testid: e.dataset.testid, tag: e.tagName, text: e.textContent.trim().slice(0, 60) }))
81
67
  ```
82
68
 
83
- #### When there is no accessible name
84
-
85
- Use a `locator` with a CSS attribute selector or ARIA role:
86
-
87
- ```yaml
88
- search field:
89
- type: 'locator'
90
- value: '[role="searchbox"]'
91
-
92
- icon button:
93
- type: 'locator'
94
- value: '[aria-label="Close"]'
95
- ```
69
+ Common fixes:
70
+ - Name mismatch → copy exact name from snapshot
71
+ - Multiple matches add `nth` or `exact: true`
72
+ - No accessible name → use `testid` or `locator` (CSS)
73
+ - Element in iframe → add `frame` field
74
+ - Dynamic content → use `testid` or structural `role` + `nth`
96
75
 
97
76
  ---
98
77
 
99
- ### Step 4: Handle Dynamic Content
78
+ ## Step 4: Table Selectors
100
79
 
101
- For elements whose text changes between test runs (list items, card data, user-generated content, timestamps):
102
-
103
- **Never use `type: text` with a specific value** — it breaks when data changes.
80
+ For table patterns, add table selectors with `columns` config:
104
81
 
105
82
  ```yaml
106
- # BAD — specific text breaks when data changes
107
- card title:
108
- type: 'text'
109
- value: 'Some specific title'
110
-
111
- # GOOD — structural: first heading inside a card container
112
- card title:
83
+ users:
113
84
  type: 'role'
114
- value: 'heading'
115
- nth: 1 # skip page-level headings, get first card heading
116
-
117
- # BEST — if the app has data-testid
118
- card title:
119
- type: 'testid'
120
- value: 'card-title'
85
+ value: 'table'
86
+ name: 'Users'
87
+ columns:
88
+ username:
89
+ index: 0
90
+ header: 'Username'
91
+ email:
92
+ index: 1
93
+ header: 'Email'
94
+ status:
95
+ index: 2
96
+ header: 'Status'
121
97
  ```
122
98
 
123
- To determine the correct `nth` offset, count how many matching elements appear before the target in the snapshot (e.g. how many headings come before the first card heading).
99
+ **How to build `columns`**: count column headers in snapshot (left to right, 0-indexed). Map each `[Col] column` reference from feature file to its index.
124
100
 
125
101
  ---
126
102
 
127
- ### Step 4b: Handle Detail Screens with Dynamic IDs
103
+ ## Step 5: Detail Screens with Dynamic IDs
128
104
 
129
- For screens like `/admin/users/:id` or `/products/:slug`:
130
- 1. Navigate to the **list page** first via MCP browser to find a real record ID
131
- 2. Use that ID in the page selector value
132
- 3. Use `User is on [X] page` — sungen resolves the path from the selector
105
+ For screens like `/admin/users/:id`:
106
+ 1. Navigate to list page via MCP to find a real record ID
107
+ 2. Hardcode the ID in page selector
133
108
 
134
109
  ```yaml
135
- # selectors.yaml — full path with real ID
136
110
  user detail:
137
111
  type: 'page'
138
112
  value: '/admin/users/de42d800-0f5a-490e-9dcf-344fedbd34a5'
139
113
  ```
140
114
 
141
- Note: the selector uses a hardcoded ID from the live page. If the record is deleted, update the ID in `selectors.yaml`.
142
-
143
- ---
144
-
145
- ### Step 5: Handle SPA / Client-side Routing
146
-
147
- Many modern apps (Next.js, Nuxt, SvelteKit, etc.) return the same HTML shell for all URLs and route client-side. `domcontentloaded` fires on the shell before the target page renders.
148
-
149
- **Symptom**: Tests see a different page than expected (e.g. home page instead of `/dashboard`).
150
-
151
- **Fix in the feature file**: Add an explicit assertion after navigation to confirm the correct page has loaded before proceeding:
152
-
153
- ```gherkin
154
- Scenario: VP-UI-001 Some test
155
- Given User is on [Dashboard] page
156
- Then User see [Dashboard Title] heading is visible ← confirms page loaded
157
- When User click [Some Button] button
158
- ...
159
- ```
160
-
161
- The "page loaded" check should use a **stable, always-visible element** on that specific page — typically the main page heading.
162
-
163
- ---
164
-
165
- ### Step 6: Handle Multiple Matches (strict mode)
166
-
167
- When an element appears more than once (e.g. desktop + mobile nav, repeated list items), add `nth`:
168
-
169
- ```yaml
170
- nav link:
171
- type: 'role'
172
- value: 'link'
173
- name: 'Dashboard'
174
- nth: 0 # first occurrence (desktop nav)
175
- ```
176
-
177
- Use `nth: 0` for the first match of dynamic/repeated elements.
178
-
179
- ---
180
-
181
- ### Auto-Infer (skip YAML entry)
182
-
183
- Many elements don't need a YAML entry — sungen auto-infers from the Gherkin label:
184
-
185
- | Gherkin | Auto-inferred locator |
186
- |---|---|
187
- | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
188
- | `[Home] link` | `getByRole('link', { name: 'Home' })` |
189
- | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
190
- | `[Email] field` | `getByPlaceholder('Email')` |
191
- | `[Success] text` / `message` / `label` | `getByText('Success')` |
192
- | `[Terms] checkbox` | `getByRole('checkbox', { name: 'Terms' })` |
193
- | `[Global] search` | `getByRole('searchbox', { name: 'Global' })` |
194
- | `[Vietnam] option` | `getByRole('option', { name: 'Vietnam' })` |
195
- | `[Price] slider` | `getByRole('slider', { name: 'Price' })` |
196
- | `[Notification] toggle` | `getByRole('switch', { name: 'Notification' })` |
197
- | `[Profile] tab` | `getByRole('tab', { name: 'Profile' })` |
198
- | `[Confirm] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'Confirm' })` |
199
-
200
- **Only add a YAML entry when auto-infer won't work:**
201
- - The accessible name differs from the Gherkin label
202
- - Needs `nth` to disambiguate
203
- - Needs `testid` or CSS locator
204
- - Is dynamic content (needs structural selector)
205
- - Is a bare input with no label or placeholder
206
-
207
- ---
208
-
209
- ### Proactive Selector Validation (before running tests)
210
-
211
- **Most failures are selector mismatches.** Validate selectors against the live page BEFORE running any test — this eliminates slow compile→run→read→fix cycles.
212
-
213
- After generating `selectors.yaml` (Step 3), verify each entry:
214
-
215
- #### How to validate
216
-
217
- Use `browser_evaluate` to check if each selector actually finds an element on the page:
218
-
219
- ```js
220
- // Validate a role selector
221
- document.querySelectorAll('[role="button"]').length;
222
- // or check accessible name exists
223
- Array.from(document.querySelectorAll('button'))
224
- .filter(el => el.textContent.includes('Submit') || el.getAttribute('aria-label')?.includes('Submit'))
225
- .length;
226
- ```
227
-
228
- Or use `browser_snapshot` and cross-check:
229
- 1. Read all `[Reference]` entries from `selectors.yaml`
230
- 2. Take a `browser_snapshot`
231
- 3. For each entry, verify:
232
- - **role + name**: does the snapshot contain `button "Submit"` or `link "Home"`?
233
- - **testid**: does `browser_evaluate` find `[data-testid="xxx"]`?
234
- - **placeholder**: does the snapshot contain a textbox with that placeholder?
235
- - **locator**: does `browser_evaluate` find `document.querySelector('xxx')`?
236
- 4. Fix mismatches immediately — no need to run tests
237
-
238
- #### What to check
239
-
240
- | Selector type | Validation method |
241
- |---|---|
242
- | `role` + `name` | Search snapshot for `role "name"` text |
243
- | `testid` | `browser_evaluate`: `document.querySelector('[data-testid="xxx"]')` |
244
- | `placeholder` | Search snapshot for textbox with placeholder |
245
- | `locator` (CSS) | `browser_evaluate`: `document.querySelector('xxx')` |
246
- | `page` | Verify URL path exists (navigate and check) |
247
-
248
- #### Common proactive fixes
249
-
250
- - Name mismatch → copy exact name from snapshot
251
- - Element not found → check if element is inside iframe/dialog (needs `frame` or scope)
252
- - Multiple matches → add `nth: 0` or `exact: true`
253
- - No accessible name → switch to `testid` or `locator`
254
-
255
- **Target: fix 80%+ of selector issues before the first test run.**
256
-
257
115
  ---
258
116
 
259
- ### Batched Test Execution
260
-
261
- After proactive validation, run tests in **batches of 20** for faster feedback:
262
-
263
- ```
264
- 1. COMPILE — sungen generate --screen <screen>
265
-
266
- 2. BATCH RUN — run 20 tests at a time:
267
- npx playwright test <spec> --grep "VP-UI-001|VP-UI-002|...|VP-UI-020" --reporter=line
268
-
269
- 3. IF FAILURES in batch:
270
- a. Group failures by root cause (same selector, same error type)
271
- b. Fix selectors.yaml or test-data.yaml
272
- c. Recompile: sungen generate --screen <screen>
273
- d. Re-run ONLY the failing tests from this batch
274
- e. If fixed → move to next batch
275
-
276
- 4. NEXT BATCH — repeat with next 20 tests (VP-UI-021...VP-UI-040)
277
-
278
- 5. FINAL CONFIRMATION — after all batches pass, run ALL tests once:
279
- npx playwright test <spec> --reporter=line
280
- This catches regressions from selector changes.
281
-
282
- 6. If still failing after 5 fix attempts per batch → ask user about direct .spec.ts fix
283
- ```
284
-
285
- #### Building batch `--grep` patterns
286
-
287
- Extract scenario names and batch them:
288
- ```bash
289
- # Batch 1: first 20
290
- npx playwright test <spec> --grep "VP-UI-001|VP-UI-002|...|VP-UI-020" --reporter=line
291
-
292
- # Batch 2: next 20
293
- npx playwright test <spec> --grep "VP-VAL-001|VP-VAL-002|...|VP-VAL-020" --reporter=line
294
- ```
295
-
296
- #### Grouping failures by root cause
297
-
298
- Common patterns where 1 fix resolves many failures:
299
- - **Same selector** — e.g., all `[Email Error]` tests fail → fix `email error` in selectors.yaml once
300
- - **Same error type** — e.g., all `strict mode violation` → add `exact: true` or `nth`
301
- - **Same assertion** — e.g., all `toHaveText` on inputs fail → change Gherkin pattern
302
-
303
- Fix the root cause first, verify with the batch, then move on.
304
-
305
- ---
117
+ ## Step 6: Fix Loop
306
118
 
307
- ### Key Rules (from sungen-selector-keys)
119
+ After fixing selectors:
120
+ 1. Recompile: `sungen generate --screen <screen>`
121
+ 2. Re-run only failing tests: `npx playwright test --grep "VP-XXX-001|VP-XXX-002" --reporter=line`
122
+ 3. If new failures → repeat (max 3 attempts)
123
+ 4. After all fixes → run ALL tests once for regression check
308
124
 
309
- - `[Reference]` lowercase, keep Unicode: `[Search Content]` `search content:`, `[Thời gian]` → `thời gian:`
310
- - Keys use **spaces** (not dots) as word separators
311
- - Same label, different element types → add `--type` suffix
312
- - Same label, nth occurrence → add `--N` suffix
125
+ If still failing after 3 attemptsask user for guidance.