@sun-asterisk/sungen 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +66 -37
  2. package/dist/cli/commands/update.d.ts +3 -0
  3. package/dist/cli/commands/update.d.ts.map +1 -0
  4. package/dist/cli/commands/update.js +21 -0
  5. package/dist/cli/commands/update.js.map +1 -0
  6. package/dist/cli/index.js +3 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/generators/gherkin-parser/index.d.ts +2 -0
  9. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  10. package/dist/generators/gherkin-parser/index.js +17 -3
  11. package/dist/generators/gherkin-parser/index.js.map +1 -1
  12. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-accept-action.hbs +1 -0
  13. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-dismiss-action.hbs +1 -0
  14. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-fill-action.hbs +1 -0
  15. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/alert-text-assertion.hbs +8 -0
  16. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +3 -0
  17. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +1 -0
  18. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +12 -1
  19. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +12 -1
  20. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  21. package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -57
  22. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  23. package/dist/generators/test-generator/patterns/index.d.ts +9 -0
  24. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  25. package/dist/generators/test-generator/patterns/index.js +32 -0
  26. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  27. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +1 -1
  28. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  29. package/dist/generators/test-generator/patterns/interaction-patterns.js +56 -1
  30. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  31. package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +1 -1
  32. package/dist/generators/test-generator/patterns/table-patterns.js +8 -5
  33. package/dist/generators/test-generator/patterns/table-patterns.js.map +1 -1
  34. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  35. package/dist/generators/test-generator/utils/selector-resolver.js +16 -0
  36. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  37. package/dist/orchestrator/ai-rules-updater.d.ts +13 -0
  38. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -0
  39. package/dist/orchestrator/ai-rules-updater.js +157 -0
  40. package/dist/orchestrator/ai-rules-updater.js.map +1 -0
  41. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  42. package/dist/orchestrator/project-initializer.js +2 -27
  43. package/dist/orchestrator/project-initializer.js.map +1 -1
  44. package/dist/orchestrator/screen-manager.d.ts +1 -0
  45. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  46. package/dist/orchestrator/screen-manager.js +70 -3
  47. package/dist/orchestrator/screen-manager.js.map +1 -1
  48. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
  49. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +11 -4
  50. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +11 -6
  51. package/dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +22 -9
  52. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +170 -24
  53. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +118 -12
  54. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +16 -2
  55. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +124 -71
  56. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -5
  57. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +12 -4
  58. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +11 -6
  59. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +22 -9
  60. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +170 -24
  61. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +93 -12
  62. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +16 -2
  63. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +124 -72
  64. package/dist/orchestrator/templates/readme.md +13 -8
  65. package/package.json +1 -1
  66. package/src/cli/commands/update.ts +18 -0
  67. package/src/cli/index.ts +3 -1
  68. package/src/generators/gherkin-parser/index.ts +20 -3
  69. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-accept-action.hbs +1 -0
  70. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-dismiss-action.hbs +1 -0
  71. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-fill-action.hbs +1 -0
  72. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/alert-text-assertion.hbs +8 -0
  73. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +3 -0
  74. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +1 -0
  75. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +12 -1
  76. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +12 -1
  77. package/src/generators/test-generator/patterns/assertion-patterns.ts +106 -65
  78. package/src/generators/test-generator/patterns/index.ts +41 -0
  79. package/src/generators/test-generator/patterns/interaction-patterns.ts +58 -1
  80. package/src/generators/test-generator/patterns/table-patterns.ts +8 -5
  81. package/src/generators/test-generator/utils/selector-resolver.ts +16 -0
  82. package/src/orchestrator/ai-rules-updater.ts +139 -0
  83. package/src/orchestrator/project-initializer.ts +2 -32
  84. package/src/orchestrator/screen-manager.ts +72 -3
  85. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
  86. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +11 -4
  87. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +11 -6
  88. package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +22 -9
  89. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +170 -24
  90. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +118 -12
  91. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +16 -2
  92. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +124 -71
  93. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -5
  94. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +12 -4
  95. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +11 -6
  96. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +22 -9
  97. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +170 -24
  98. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +93 -12
  99. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +16 -2
  100. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +124 -72
  101. package/src/orchestrator/templates/readme.md +13 -8
  102. package/docs/gherkin standards/gherkin-core-standard.md +0 -428
  103. package/docs/gherkin standards/gherkin-core-standard.vi.md +0 -513
  104. package/docs/gherkin-dictionary.md +0 -1071
  105. package/docs/makeauth.md +0 -225
@@ -4,13 +4,35 @@ description: 'Sungen Gherkin patterns, selector types, and YAML key rules. Use t
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
- ## Step Patterns (65 patterns)
7
+ ## Standard Syntax
8
+
9
+ ```
10
+ [Keyword] User <Action> [Target Name] <Target Type> <in [Parent Name] <Parent Type>> <with {{Value}}> <is State>
11
+ ```
12
+
13
+ - **Actor**: Always `User`, always active voice.
14
+ - **Value**: `with {{snake_case}}` — never hardcode static data.
15
+ - **State**: `is <keyword>` — never use `{{}}` for states.
16
+ - **Parent scope**: `in [Parent] parentType` — optional, only when page has 2+ similar blocks needing disambiguation.
17
+
18
+ ## Keyword → Action Rules
19
+
20
+ ```
21
+ GIVEN → is on
22
+ WHEN → click · fill · select · press · clear · check · uncheck · hover
23
+ [⚠️ wait for — only for Spinner/Modal, minimize usage]
24
+ THEN → see
25
+ AND → inherits from preceding keyword
26
+ ```
27
+
28
+ ## Step Patterns (70 patterns)
8
29
 
9
30
  ### Setup
10
31
 
11
32
  ```
12
33
  User is on [T] page # navigate to page
13
34
  User is on [T] page with {{v}} # navigate with data (e.g., detail page with ID)
35
+ User is on [T] dialog # enter dialog scope
14
36
  User is logged in | is not logged in # auth state
15
37
  ```
16
38
 
@@ -18,31 +40,57 @@ User is logged in | is not logged in # auth state
18
40
 
19
41
  ```
20
42
  User fill [T] field with {{v}} # text input
43
+ User fill [T] textarea with {{v}} # multiline input
44
+ User fill [T] search with {{v}} # search input
45
+ User fill [T] slider with {{v}} # set slider value
46
+ User fill [T] date picker with {{v}} # date input
21
47
  User clear [T] field # clear input
22
48
  User check [T] checkbox # check
49
+ User check [T] toggle # toggle on (same as check)
50
+ User check [T] radio # select radio
23
51
  User uncheck [T] checkbox # uncheck
52
+ User uncheck [T] toggle # toggle off
24
53
  User select [T] dropdown with {{v}} # select option
25
- User toggle [T] switch # toggle switch/checkbox
26
- User upload [T] file with {{f}} # file upload
54
+ User upload [T] uploader with {{f}} # file upload
27
55
  ```
28
56
 
29
57
  ### Interaction
30
58
 
31
59
  ```
32
- User click [T] button # click
33
- User click [T] button with {{v}} # click with text match
60
+ User click [T] button # click (static element, no value)
61
+ User click [T] row with {{v}} # click dynamic list item (row/item/card/option)
62
+ User click [T] tab # switch tab
63
+ User click [T] column # sort column
64
+ User click [T] breadcrumb # navigate breadcrumb
34
65
  User double click [T] element # double click
35
- User hover [T] icon # hover
66
+ User hover [T] icon # hover (must have see/click after)
67
+ User hover [T] row # hover row for hidden actions
36
68
  User drag [T] to [T2] # drag and drop
37
69
  User expand [T] row # expand (aria-expanded)
38
70
  User collapse [T] row # collapse (aria-expanded)
39
71
  ```
40
72
 
73
+ #### click + with {{Value}} rule
74
+
75
+ - **NO value** for static elements: `button`, `link`, `icon`, `tab`, `toggle`
76
+ - **WITH value** only for dynamic lists: `row`, `item`, `card`, `option`
77
+
78
+ ### Browser Alert (system dialog)
79
+
80
+ ```
81
+ User click [OK] alert # accept (OK/Accept/Yes/Confirm)
82
+ User click [Cancel] alert # dismiss (Cancel/Dismiss/No)
83
+ User fill [T] alert with {{v}} # fill prompt + accept
84
+ User see [message text] alert # assert dialog message
85
+ ```
86
+
87
+ > Alert steps must appear BEFORE the action that triggers the dialog.
88
+
41
89
  ### Keyboard
42
90
 
43
91
  ```
44
- User press Escape key # global key press
45
- User press Enter on [T] field # key on element
92
+ User press [Escape] key # global key press
93
+ User press [Enter] on [T] field # key on element
46
94
  ```
47
95
 
48
96
  ### Wait
@@ -53,53 +101,129 @@ User wait for [T] dialog # wait for element
53
101
  User wait for [T] dialog is STATE # wait for state
54
102
  User wait for [T] dialog with {{v}} # wait for element with text
55
103
  User wait for [T] page # wait for navigation
104
+ User wait for [T] message # wait for toast/feedback
105
+ User wait for [T] button # wait for button to appear
56
106
  ```
57
107
 
58
108
  ### Scroll & Frame
59
109
 
60
110
  ```
61
111
  User scroll to [T] section # scroll into view
62
- User switch to [T] frame # enter/exit iframe
112
+ User switch to [T] frame # enter iframe
113
+ User switch to [main] frame # exit iframe
63
114
  ```
64
115
 
65
- ### Assertions
116
+ ### Assertions (8 verify patterns)
66
117
 
67
118
  ```
68
- User see [T] page # URL assertion
69
- User see [T] heading # visibility
70
- User see [T] heading with {{v}} # visibility + text
119
+ # 1. Visibility
120
+ User see [T] message # visible (default — NEVER add "is visible")
121
+ User see [T] modal is hidden # hidden
122
+
123
+ # 2. Text Content (exact full match — toHaveText)
124
+ User see [T] message with {{v}} # exact text match
125
+ User see [T] header with {{v}} # heading text
126
+ User see [T] label with {{v}} # label text
127
+
128
+ # 3. Partial Text Match (toContainText)
71
129
  User see [T] text contains {{v}} # partial text match
72
- User see [T] text has text {{v}} # exact text match
73
- User see [T] button is STATE # state assertion
74
- User see [T] dialog with {{v}} is STATE # text + state
75
- User see {{v}} # see data text
130
+
131
+ # 4. Input Value (toHaveValue)
132
+ User see [T] field with {{v}} # input value
133
+ User see [T] dropdown with {{v}} # selected value
134
+ User see [T] date picker with {{v}} # date value
135
+ User see [T] search with {{v}} # search input value
136
+ User see [T] slider with {{v}} # slider value
137
+
138
+ # 5. Component State
139
+ User see [T] button is disabled # state assertion
140
+ User see [T] checkbox is checked # checked state
141
+ User see [T] toggle is unchecked # unchecked state
142
+ User see [T] dialog with {{v}} is hidden # text + state combined
143
+
144
+ # 6. Attribute (toHaveAttribute — when selector YAML has `attribute` field)
145
+ User see [T] image with {{v}} # image src
146
+ User see [T] link with {{v}} # link href
147
+
148
+ # 7. Count
149
+ User see [T] row with {{count}} # element count
150
+
151
+ # 8. Page Context
152
+ User see [T] page # URL assertion
76
153
  ```
77
154
 
78
155
  ### Table
79
156
 
80
157
  ```
81
- User see [Table] table has row with {{f}} # row exists
158
+ User see [Col] column in [Table] table # column exists (parent scoping)
159
+ User see [Table] table row with {{f}} # row exists
82
160
  User see [Table] table has no row with {{f}} # row not exists
83
- User see [Table] table has {{count}} rows # row count
84
- User see [Table] table has [Col] column # column exists
161
+ User see [Table] table with {{count}} rows # row count
85
162
  User see [Table] table is empty # empty table
86
163
  User see [Table] table row with {{f}} has [Col] with {{v}} # cell by filter
87
164
  User see [Table] table row 1 [Col] cell with {{v}} # cell by index
88
165
  User click [Act] in [Table] table row with {{f}} # action in row
89
166
  ```
90
167
 
168
+ ### Parent Scoping (disambiguation)
169
+
170
+ ```
171
+ User click [Submit] button in [User Info] form # button inside specific form
172
+ User fill [Email] field in [Registration] form with {{v}} # field inside specific form
173
+ User see [Total] text in [Summary] section with {{v}} # text inside specific section
174
+ User click [Delete] button in [Active Users] table # button inside specific table
175
+ ```
176
+
177
+ - **Optional** — only use when page has 2+ similar UI blocks
178
+ - **Valid parent types**: `table`, `list`, `section`, `dialog`, `form`
179
+ - **Max 2 levels**: `[Target] in [Parent]`. **NEVER** nest 3 levels: `[A] in [B] in [C]`
180
+ - Parent resolves from selectors YAML first, falls back to auto-infer `getByRole(parentType, { name })`
181
+
91
182
  ### States
92
183
 
93
184
  `hidden` `visible` `disabled` `enabled` `checked` `unchecked` `focused` `empty` `loading` `selected` `sorted ascending` `sorted descending`
94
185
 
95
186
  ### Element Types
96
187
 
97
- `page` `button` `link` `field` `textarea` `heading` `text` `checkbox` `radio` `switch` `dropdown` `dialog` `modal` `menu` `menuitem` `tab` `tabpanel` `table` `row` `cell` `list` `listitem` `icon` `image` `alert` `spinner` `progressbar` `section` `region` `nav` `frame` `uploader` `file` `columnheader` `tooltip` `slider` `treeitem`
188
+ | Group | Types |
189
+ |---|---|
190
+ | **Context** | `page` `dialog` `modal` `drawer` `tab` `alert` `overlay` `step` |
191
+ | **Input** | `field` `textarea` `search` `dropdown` `option` `checkbox` `radio` `toggle` `uploader` `slider` `date-picker` |
192
+ | **Trigger** | `button` `link` `icon` `menuitem` `tag` |
193
+ | **Data** | `table` `row` `column` `cell` `list` `item` `card` `section` |
194
+ | **Feedback** | `message` `header` `label` `text` `tooltip` `badge` `breadcrumb` `image` |
195
+ | **System** | `key` `frame` `spinner` `progressbar` |
196
+
197
+ ### Auto-infer (no YAML entry needed)
198
+
199
+ | Gherkin | Playwright locator |
200
+ |---|---|
201
+ | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
202
+ | `[Home] link` | `getByRole('link', { name: 'Home' })` |
203
+ | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
204
+ | `[Email] field` | `getByPlaceholder('Email')` |
205
+ | `[Success] text` / `message` / `label` | `getByText('Success')` |
206
+ | `[Terms] checkbox` | `getByRole('checkbox', { name: 'Terms' })` |
207
+ | `[Male] radio` | `getByRole('radio', { name: 'Male' })` |
208
+ | `[Global] search` | `getByRole('searchbox', { name: 'Global' })` |
209
+ | `[Vietnam] option` | `getByRole('option', { name: 'Vietnam' })` |
210
+ | `[Price] slider` | `getByRole('slider', { name: 'Price' })` |
211
+ | `[Notification] toggle` | `getByRole('switch', { name: 'Notification' })` |
212
+ | `[Profile] tab` | `getByRole('tab', { name: 'Profile' })` |
213
+ | `[Orders] table` | `getByRole('table', { name: 'Orders' })` |
214
+ | `[Products] list` | `getByRole('list', { name: 'Products' })` |
215
+ | `[Name] column` | `getByRole('columnheader', { name: 'Name' })` |
216
+ | `[Confirm] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'Confirm' })` |
98
217
 
99
218
  ## YAML Keys
100
219
 
101
220
  `[Reference]` → **lowercase, keep Unicode**: `[Search Content]` → `search content:`, `[Thời gian]` → `thời gian:`
102
221
 
222
+ - Keys use **spaces** (not dots) as word separators
223
+ - Same label, different element types → add `--type` suffix
224
+ - Same label, nth occurrence → add `--N` suffix
225
+ - Target Name > 30 chars → shorten to 1–3 meaningful words
226
+
103
227
  ## Selectors (priority order)
104
228
 
105
229
  | type | value | name | use |
@@ -120,8 +244,30 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
120
244
 
121
245
  | Tag | Effect |
122
246
  |---|---|
247
+ | `@auto` | Standard scenario, ready for automation |
248
+ | `@manual` | Skip in generation |
249
+ | `@smoke` / `@regression` | Test suite grouping |
123
250
  | `@auth:role` | Use auth storage state for role |
124
251
  | `@no-auth` | Disable inherited auth |
125
- | `@steps:name` | Define reusable step block |
126
- | `@extend:name` | Prepend steps from @steps block |
127
- | `@manual` | Skip in generation |
252
+ | `@steps:name` | Define reusable step block (base scenario) |
253
+ | `@extend:name` | Prepend Given→When from @steps block (skip Then) |
254
+
255
+ ### @extend behavior
256
+
257
+ - Tool executes **only Given→When** of `@steps` scenario (skips Then)
258
+ - The `Given` in `@extend` scenario is the **entry assertion** (confirms state after base steps)
259
+ - If `@steps` scenario fails, `@extend` scenario is **skipped**
260
+ - Name format: `snake_case` or `kebab-case` with module prefix: `@steps:kudos__open_modal`
261
+
262
+ ## Common Syntax Errors
263
+
264
+ | Error | Wrong | Correct |
265
+ |---|---|---|
266
+ | Wrong keyword | `Given User click [T] button` | `When User click [T] button` |
267
+ | Wrong action for type | `When User click [T] checkbox` | `When User check [T] checkbox` |
268
+ | press wrong target | `When User press [Submit] button` | `When User press [Enter] key` |
269
+ | uncheck radio | `When User uncheck [Male] radio` | `When User check [Female] radio` |
270
+ | Hardcode data | `with {{admin@mail.com}}` | `with {{invalid_email}}` |
271
+ | Missing `is` for state | `with {{text}} hidden` | `with {{text}} is hidden` |
272
+ | State as value | `with {{disabled}}` | `is disabled` |
273
+ | Missing target type | `fill [email] with {{v}}` | `fill [email] field with {{v}}` |
@@ -124,6 +124,24 @@ To determine the correct `nth` offset, count how many matching elements appear b
124
124
 
125
125
  ---
126
126
 
127
+ ### Step 4b: Handle Detail Screens with Dynamic IDs
128
+
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
133
+
134
+ ```yaml
135
+ # selectors.yaml — full path with real ID
136
+ user detail:
137
+ type: 'page'
138
+ value: '/admin/users/de42d800-0f5a-490e-9dcf-344fedbd34a5'
139
+ ```
140
+
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
+
127
145
  ### Step 5: Handle SPA / Client-side Routing
128
146
 
129
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.
@@ -168,9 +186,16 @@ Many elements don't need a YAML entry — sungen auto-infers from the Gherkin la
168
186
  |---|---|
169
187
  | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
170
188
  | `[Home] link` | `getByRole('link', { name: 'Home' })` |
171
- | `[Welcome] heading` | `getByRole('heading', { name: 'Welcome' })` |
189
+ | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
172
190
  | `[Email] field` | `getByPlaceholder('Email')` |
173
- | `[Success] text` | `getByText('Success')` |
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' })` |
174
199
 
175
200
  **Only add a YAML entry when auto-infer won't work:**
176
201
  - The accessible name differs from the Gherkin label
@@ -181,20 +206,76 @@ Many elements don't need a YAML entry — sungen auto-infers from the Gherkin la
181
206
 
182
207
  ---
183
208
 
184
- ### Fix Loop on Test Failure
209
+ ### Proactive Selector Validation (before running tests)
185
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
223
+ Array.from(document.querySelectorAll('button'))
224
+ .filter(el => el.textContent.includes('Submit') || el.getAttribute('aria-label')?.includes('Submit'))
225
+ .length;
186
226
  ```
187
- attempt = 0
188
- while attempt < 5:
189
- compile run test
190
- if pass done
191
- read error-context.md in test-results/ check exact snapshot state at failure time
192
- fix selectors.yaml or test-data.yaml
193
- recompile → attempt++
194
- if still failing → ask user about direct .spec.ts fix
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 the element exists in the snapshot
232
+ 4. Fix mismatches immediately — no test run needed
233
+
234
+ #### What to check
235
+
236
+ | Selector type | Validation method |
237
+ |---|---|
238
+ | `role` + `name` | Search snapshot for `role "name"` text |
239
+ | `testid` | `browser_evaluate`: `document.querySelector('[data-testid="xxx"]')` |
240
+ | `placeholder` | Search snapshot for textbox with placeholder |
241
+ | `locator` (CSS) | `browser_evaluate`: `document.querySelector('xxx')` |
242
+
243
+ **Target: fix 80%+ of selector issues before the first test run.**
244
+
245
+ ---
246
+
247
+ ### Batched Test Execution
248
+
249
+ After proactive validation, run tests in **batches of 20** for faster feedback:
250
+
195
251
  ```
252
+ 1. COMPILE — sungen generate --screen <screen>
253
+
254
+ 2. BATCH RUN — run 20 tests at a time:
255
+ npx playwright test <spec> --grep "VP-UI-001|VP-UI-002|...|VP-UI-020" --reporter=line
256
+
257
+ 3. IF FAILURES in batch:
258
+ a. Group failures by root cause (same selector, same error type)
259
+ b. Fix selectors.yaml or test-data.yaml
260
+ c. Recompile, re-run only failing tests from this batch
261
+ d. If fixed → move to next batch
262
+
263
+ 4. NEXT BATCH — repeat with next 20 tests
264
+
265
+ 5. FINAL CONFIRMATION — run ALL tests once:
266
+ npx playwright test <spec> --reporter=line
267
+
268
+ 6. If still failing after 5 fix attempts per batch → ask user about direct .spec.ts fix
269
+ ```
270
+
271
+ #### Grouping failures by root cause
272
+
273
+ Common patterns where 1 fix resolves many failures:
274
+ - **Same selector** — e.g., all `[Email Error]` tests fail → fix once
275
+ - **Same error type** — e.g., all `strict mode violation` → add `exact: true` or `nth`
276
+ - **Same assertion** — e.g., all `toHaveText` on inputs fail → change Gherkin pattern
196
277
 
197
- **Always read the error context snapshot first** it shows the exact page state when the test failed, which is more reliable than re-navigating with MCP.
278
+ Fix the root cause first, verify with the batch, then move on.
198
279
 
199
280
  ---
200
281
 
@@ -51,6 +51,10 @@ Type aliases (normalized automatically):
51
51
  | logo, image, icon | `img` |
52
52
  | btn | `button` |
53
53
  | input, textbox, textarea, editor | `field` |
54
+ | search | `searchbox` |
55
+ | toggle | `switch` |
56
+ | alert | `alertdialog` |
57
+ | modal, drawer | `dialog` |
54
58
  | column | `columnheader` |
55
59
  | list-item | `listitem` |
56
60
 
@@ -83,10 +87,20 @@ If no YAML key exists, the resolver infers from the Gherkin element type:
83
87
  |---|---|
84
88
  | `[X] button` | `getByRole('button', { name: 'X' })` |
85
89
  | `[X] link` | `getByRole('link', { name: 'X' })` |
86
- | `[X] heading` | `getByRole('heading', { name: 'X' })` |
90
+ | `[X] heading` / `header` | `getByRole('heading', { name: 'X' })` |
87
91
  | `[X] checkbox` | `getByRole('checkbox', { name: 'X' })` |
92
+ | `[X] radio` | `getByRole('radio', { name: 'X' })` |
88
93
  | `[X] field` | `getByPlaceholder('X')` |
89
- | `[X] text` | `getByText('X')` |
94
+ | `[X] text` / `message` / `label` | `getByText('X')` |
90
95
  | `[X] logo/image/icon` | `getByRole('img', { name: 'X' })` |
96
+ | `[X] search` | `getByRole('searchbox', { name: 'X' })` |
97
+ | `[X] option` | `getByRole('option', { name: 'X' })` |
98
+ | `[X] slider` | `getByRole('slider', { name: 'X' })` |
99
+ | `[X] toggle` | `getByRole('switch', { name: 'X' })` |
100
+ | `[X] tab` | `getByRole('tab', { name: 'X' })` |
101
+ | `[X] table` | `getByRole('table', { name: 'X' })` |
102
+ | `[X] list` | `getByRole('list', { name: 'X' })` |
103
+ | `[X] column` | `getByRole('columnheader', { name: 'X' })` |
104
+ | `[X] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'X' })` |
91
105
 
92
106
  **Only add a YAML entry when** the auto-inferred locator won't work (wrong name, need testid, need nth, etc.).