@sun-asterisk/sungen 2.2.2 → 2.2.3

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 (53) hide show
  1. package/README.md +63 -34
  2. package/dist/cli/index.js +1 -1
  3. package/dist/generators/gherkin-parser/index.js +1 -1
  4. package/dist/generators/gherkin-parser/index.js.map +1 -1
  5. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-accept-action.hbs +1 -0
  6. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-dismiss-action.hbs +1 -0
  7. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/alert-fill-action.hbs +1 -0
  8. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/alert-text-assertion.hbs +8 -0
  9. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +1 -0
  10. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  11. package/dist/generators/test-generator/patterns/assertion-patterns.js +83 -57
  12. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  13. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +1 -1
  14. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  15. package/dist/generators/test-generator/patterns/interaction-patterns.js +56 -1
  16. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  17. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  18. package/dist/generators/test-generator/utils/selector-resolver.js +16 -0
  19. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  20. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +11 -4
  21. package/dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +22 -9
  22. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +148 -21
  23. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +51 -11
  24. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +16 -2
  25. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +11 -4
  26. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +22 -9
  27. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +148 -21
  28. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +51 -11
  29. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +16 -2
  30. package/docs/gherkin standards/gherkin-core-standard.md +163 -160
  31. package/docs/gherkin standards/gherkin-core-standard.vi.md +290 -404
  32. package/docs/gherkin-dictionary.md +71 -16
  33. package/package.json +1 -1
  34. package/src/cli/index.ts +1 -1
  35. package/src/generators/gherkin-parser/index.ts +1 -1
  36. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-accept-action.hbs +1 -0
  37. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-dismiss-action.hbs +1 -0
  38. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/alert-fill-action.hbs +1 -0
  39. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/alert-text-assertion.hbs +8 -0
  40. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +1 -0
  41. package/src/generators/test-generator/patterns/assertion-patterns.ts +93 -65
  42. package/src/generators/test-generator/patterns/interaction-patterns.ts +58 -1
  43. package/src/generators/test-generator/utils/selector-resolver.ts +16 -0
  44. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +11 -4
  45. package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +22 -9
  46. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +148 -21
  47. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +51 -11
  48. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +16 -2
  49. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +11 -4
  50. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +22 -9
  51. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +148 -21
  52. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +51 -11
  53. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +16 -2
@@ -4,13 +4,34 @@ description: 'Sungen Gherkin patterns, selector types, and YAML key rules. Auto-
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> <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
+
17
+ ## Keyword → Action Rules
18
+
19
+ ```
20
+ GIVEN → is on
21
+ WHEN → click · fill · select · press · clear · check · uncheck · hover
22
+ [⚠️ wait for — only for Spinner/Modal, minimize usage]
23
+ THEN → see
24
+ AND → inherits from preceding keyword
25
+ ```
26
+
27
+ ## Step Patterns (70 patterns)
8
28
 
9
29
  ### Setup
10
30
 
11
31
  ```
12
32
  User is on [T] page # navigate to page
13
33
  User is on [T] page with {{v}} # navigate with data (e.g., detail page with ID)
34
+ User is on [T] dialog # enter dialog scope
14
35
  User is logged in | is not logged in # auth state
15
36
  ```
16
37
 
@@ -18,31 +39,57 @@ User is logged in | is not logged in # auth state
18
39
 
19
40
  ```
20
41
  User fill [T] field with {{v}} # text input
42
+ User fill [T] textarea with {{v}} # multiline input
43
+ User fill [T] search with {{v}} # search input
44
+ User fill [T] slider with {{v}} # set slider value
45
+ User fill [T] date picker with {{v}} # date input
21
46
  User clear [T] field # clear input
22
47
  User check [T] checkbox # check
48
+ User check [T] toggle # toggle on (same as check)
49
+ User check [T] radio # select radio
23
50
  User uncheck [T] checkbox # uncheck
51
+ User uncheck [T] toggle # toggle off
24
52
  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
53
+ User upload [T] uploader with {{f}} # file upload
27
54
  ```
28
55
 
29
56
  ### Interaction
30
57
 
31
58
  ```
32
- User click [T] button # click
33
- User click [T] button with {{v}} # click with text match
59
+ User click [T] button # click (static element, no value)
60
+ User click [T] row with {{v}} # click dynamic list item (row/item/card/option)
61
+ User click [T] tab # switch tab
62
+ User click [T] column # sort column
63
+ User click [T] breadcrumb # navigate breadcrumb
34
64
  User double click [T] element # double click
35
- User hover [T] icon # hover
65
+ User hover [T] icon # hover (must have see/click after)
66
+ User hover [T] row # hover row for hidden actions
36
67
  User drag [T] to [T2] # drag and drop
37
68
  User expand [T] row # expand (aria-expanded)
38
69
  User collapse [T] row # collapse (aria-expanded)
39
70
  ```
40
71
 
72
+ #### click + with {{Value}} rule
73
+
74
+ - **NO value** for static elements: `button`, `link`, `icon`, `tab`, `toggle`
75
+ - **WITH value** only for dynamic lists: `row`, `item`, `card`, `option`
76
+
77
+ ### Browser Alert (system dialog)
78
+
79
+ ```
80
+ User click [OK] alert # accept (OK/Accept/Yes/Confirm)
81
+ User click [Cancel] alert # dismiss (Cancel/Dismiss/No)
82
+ User fill [T] alert with {{v}} # fill prompt + accept
83
+ User see [message text] alert # assert dialog message
84
+ ```
85
+
86
+ > Alert steps must appear BEFORE the action that triggers the dialog.
87
+
41
88
  ### Keyboard
42
89
 
43
90
  ```
44
- User press Escape key # global key press
45
- User press Enter on [T] field # key on element
91
+ User press [Escape] key # global key press
92
+ User press [Enter] on [T] field # key on element
46
93
  ```
47
94
 
48
95
  ### Wait
@@ -53,26 +100,51 @@ User wait for [T] dialog # wait for element
53
100
  User wait for [T] dialog is STATE # wait for state
54
101
  User wait for [T] dialog with {{v}} # wait for element with text
55
102
  User wait for [T] page # wait for navigation
103
+ User wait for [T] message # wait for toast/feedback
104
+ User wait for [T] button # wait for button to appear
56
105
  ```
57
106
 
58
107
  ### Scroll & Frame
59
108
 
60
109
  ```
61
110
  User scroll to [T] section # scroll into view
62
- User switch to [T] frame # enter/exit iframe
111
+ User switch to [T] frame # enter iframe
112
+ User switch to [main] frame # exit iframe
63
113
  ```
64
114
 
65
- ### Assertions
115
+ ### Assertions (6 verify patterns)
66
116
 
67
117
  ```
68
- User see [T] page # URL assertion
69
- User see [T] heading # visibility
70
- User see [T] heading with {{v}} # visibility + text
118
+ # 1. Visibility
119
+ User see [T] message # visible (default)
120
+ User see [T] modal is hidden # hidden
121
+
122
+ # 2. Text Content (exact full match — toHaveText)
123
+ User see [T] message with {{v}} # exact text match
124
+ User see [T] header with {{v}} # heading text
125
+ User see [T] label with {{v}} # label text
126
+
127
+ # 3. Partial Text Match (toContainText)
71
128
  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
129
+
130
+ # 4. Input Value (toHaveValue)
131
+ User see [T] field with {{v}} # input value
132
+ User see [T] dropdown with {{v}} # selected value
133
+ User see [T] date picker with {{v}} # date value
134
+ User see [T] search with {{v}} # search input value
135
+ User see [T] slider with {{v}} # slider value
136
+
137
+ # 5. Component State
138
+ User see [T] button is disabled # state assertion
139
+ User see [T] checkbox is checked # checked state
140
+ User see [T] toggle is unchecked # unchecked state
141
+ User see [T] dialog with {{v}} is hidden # text + state combined
142
+
143
+ # 6. Count
144
+ User see [T] row with {{count}} # element count
145
+
146
+ # 7. Page Context
147
+ User see [T] page # URL assertion
76
148
  ```
77
149
 
78
150
  ### Table
@@ -94,12 +166,45 @@ User click [Act] in [Table] table row with {{f}} # action in row
94
166
 
95
167
  ### Element Types
96
168
 
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`
169
+ | Group | Types |
170
+ |---|---|
171
+ | **Context** | `page` `dialog` `modal` `drawer` `tab` `alert` `overlay` `step` |
172
+ | **Input** | `field` `textarea` `search` `dropdown` `option` `checkbox` `radio` `toggle` `uploader` `slider` `date-picker` |
173
+ | **Trigger** | `button` `link` `icon` `menuitem` `tag` |
174
+ | **Data** | `table` `row` `column` `cell` `list` `item` `card` `section` |
175
+ | **Feedback** | `message` `header` `label` `text` `tooltip` `badge` `breadcrumb` `image` |
176
+ | **System** | `key` `frame` `spinner` `progressbar` |
177
+
178
+ ### Auto-infer (no YAML entry needed)
179
+
180
+ | Gherkin | Playwright locator |
181
+ |---|---|
182
+ | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
183
+ | `[Home] link` | `getByRole('link', { name: 'Home' })` |
184
+ | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
185
+ | `[Email] field` | `getByPlaceholder('Email')` |
186
+ | `[Success] text` / `message` / `label` | `getByText('Success')` |
187
+ | `[Terms] checkbox` | `getByRole('checkbox', { name: 'Terms' })` |
188
+ | `[Male] radio` | `getByRole('radio', { name: 'Male' })` |
189
+ | `[Global] search` | `getByRole('searchbox', { name: 'Global' })` |
190
+ | `[Vietnam] option` | `getByRole('option', { name: 'Vietnam' })` |
191
+ | `[Price] slider` | `getByRole('slider', { name: 'Price' })` |
192
+ | `[Notification] toggle` | `getByRole('switch', { name: 'Notification' })` |
193
+ | `[Profile] tab` | `getByRole('tab', { name: 'Profile' })` |
194
+ | `[Orders] table` | `getByRole('table', { name: 'Orders' })` |
195
+ | `[Products] list` | `getByRole('list', { name: 'Products' })` |
196
+ | `[Name] column` | `getByRole('columnheader', { name: 'Name' })` |
197
+ | `[Confirm] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'Confirm' })` |
98
198
 
99
199
  ## YAML Keys
100
200
 
101
201
  `[Reference]` → **lowercase, keep Unicode**: `[Search Content]` → `search content:`, `[Thời gian]` → `thời gian:`
102
202
 
203
+ - Keys use **spaces** (not dots) as word separators
204
+ - Same label, different element types → add `--type` suffix
205
+ - Same label, nth occurrence → add `--N` suffix
206
+ - Target Name > 30 chars → shorten to 1–3 meaningful words
207
+
103
208
  ## Selectors (priority order)
104
209
 
105
210
  | type | value | name | use |
@@ -120,8 +225,30 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
120
225
 
121
226
  | Tag | Effect |
122
227
  |---|---|
228
+ | `@auto` | Standard scenario, ready for automation |
229
+ | `@manual` | Skip in generation |
230
+ | `@smoke` / `@regression` | Test suite grouping |
123
231
  | `@auth:role` | Use auth storage state for role |
124
232
  | `@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 |
233
+ | `@steps:name` | Define reusable step block (base scenario) |
234
+ | `@extend:name` | Prepend Given→When from @steps block (skip Then) |
235
+
236
+ ### @extend behavior
237
+
238
+ - Tool executes **only Given→When** of `@steps` scenario (skips Then)
239
+ - The `Given` in `@extend` scenario is the **entry assertion** (confirms state after base steps)
240
+ - If `@steps` scenario fails, `@extend` scenario is **skipped**
241
+ - Name format: `snake_case` or `kebab-case` with module prefix: `@steps:kudos__open_modal`
242
+
243
+ ## Common Syntax Errors
244
+
245
+ | Error | Wrong | Correct |
246
+ |---|---|---|
247
+ | Wrong keyword | `Given User click [T] button` | `When User click [T] button` |
248
+ | Wrong action for type | `When User click [T] checkbox` | `When User check [T] checkbox` |
249
+ | press wrong target | `When User press [Submit] button` | `When User press [Enter] key` |
250
+ | uncheck radio | `When User uncheck [Male] radio` | `When User check [Female] radio` |
251
+ | Hardcode data | `with {{admin@mail.com}}` | `with {{invalid_email}}` |
252
+ | Missing `is` for state | `with {{text}} hidden` | `with {{text}} is hidden` |
253
+ | State as value | `with {{disabled}}` | `is disabled` |
254
+ | Missing target type | `fill [email] with {{v}}` | `fill [email] field with {{v}}` |
@@ -168,9 +168,16 @@ Many elements don't need a YAML entry — sungen auto-infers from the Gherkin la
168
168
  |---|---|
169
169
  | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
170
170
  | `[Home] link` | `getByRole('link', { name: 'Home' })` |
171
- | `[Welcome] heading` | `getByRole('heading', { name: 'Welcome' })` |
171
+ | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
172
172
  | `[Email] field` | `getByPlaceholder('Email')` |
173
- | `[Success] text` | `getByText('Success')` |
173
+ | `[Success] text` / `message` / `label` | `getByText('Success')` |
174
+ | `[Terms] checkbox` | `getByRole('checkbox', { name: 'Terms' })` |
175
+ | `[Global] search` | `getByRole('searchbox', { name: 'Global' })` |
176
+ | `[Vietnam] option` | `getByRole('option', { name: 'Vietnam' })` |
177
+ | `[Price] slider` | `getByRole('slider', { name: 'Price' })` |
178
+ | `[Notification] toggle` | `getByRole('switch', { name: 'Notification' })` |
179
+ | `[Profile] tab` | `getByRole('tab', { name: 'Profile' })` |
180
+ | `[Confirm] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'Confirm' })` |
174
181
 
175
182
  **Only add a YAML entry when auto-infer won't work:**
176
183
  - The accessible name differs from the Gherkin label
@@ -181,19 +188,52 @@ Many elements don't need a YAML entry — sungen auto-infers from the Gherkin la
181
188
 
182
189
  ---
183
190
 
184
- ### Fix Loop on Test Failure
191
+ ### Fix Loop on Test Failure (Batched Strategy)
185
192
 
193
+ Running all tests every iteration is slow. Use a batched approach to fix faster:
194
+
195
+ ```
196
+ 1. INITIAL RUN — run ALL tests, collect full failure list
197
+ npx playwright test <spec> --reporter=line
198
+
199
+ 2. BATCHED FIX LOOP (max 5 attempts):
200
+ a. Read test output → group failures by root cause:
201
+ - Same selector broken → 1 fix covers many tests
202
+ - Same error type (strict mode, timeout, text mismatch)
203
+ b. Fix selectors.yaml or test-data.yaml for current batch
204
+ c. Recompile: sungen generate --screen <screen>
205
+ d. Re-run ONLY previously-failing tests (max 20):
206
+ npx playwright test <spec> --grep "VP-UI-001|VP-UI-002|VP-VAL-001" --reporter=line
207
+ e. If batch passes → pick next batch of remaining failures
208
+ f. If batch still fails → fix and retry (counts toward max 5)
209
+
210
+ 3. FINAL CONFIRMATION — run ALL tests once:
211
+ npx playwright test <spec> --reporter=line
212
+ This catches regressions from selector changes.
213
+
214
+ 4. If still failing after 5 fix attempts → ask user about direct .spec.ts fix
186
215
  ```
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
216
+
217
+ #### Building the `--grep` pattern
218
+
219
+ Extract scenario names from the failure output and join with `|`:
220
+ ```bash
221
+ # Example: re-run only 3 failing tests
222
+ npx playwright test <spec> --grep "VP-VAL-001|VP-VAL-002|VP-VAL-003" --reporter=line
195
223
  ```
196
224
 
225
+ - Max 20 test names per `--grep` to keep the pattern manageable
226
+ - If >20 failures share the same root cause, fix the cause and run the first 20 to verify
227
+
228
+ #### Grouping failures by root cause
229
+
230
+ Common patterns where 1 fix resolves many failures:
231
+ - **Same selector** — e.g., all `[Email Error]` tests fail → fix `email error` in selectors.yaml once
232
+ - **Same error type** — e.g., all `strict mode violation` → add `exact: true` or `nth`
233
+ - **Same assertion** — e.g., all `toHaveText` on inputs fail → change Gherkin pattern (inputs have no text)
234
+
235
+ Fix the root cause first, verify with the batch, then move on.
236
+
197
237
  **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.
198
238
 
199
239
  ---
@@ -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.).
@@ -21,7 +21,14 @@ You are a **Senior Developer** specialized in Playwright test debugging. You gen
21
21
  1. Verify `qa/screens/${input:screen}/` has `.feature` + `test-data.yaml`. If not → run `/sungen-make-tc` first.
22
22
  2. Explore live page via #tool:playwright to generate `selectors.yaml` (per `sungen-selector-fix` skill).
23
23
  3. Compile with #tool:terminal: `sungen generate --screen ${input:screen}`
24
- 4. Run with #tool:terminal: `npx playwright test specs/generated/${input:screen}/*.spec.ts`
25
- 5. If fail → fix selectors/test-data per `sungen-selector-fix` + `sungen-error-mapping` skills, retry (max 5).
26
- 6. After 5 fails ask user about direct `.spec.ts` fix.
27
- 7. Show: pass/fail, attempt count, files changed.
24
+ 4. **Initial run** run ALL tests to get the full failure picture:
25
+ `npx playwright test specs/generated/${input:screen}/*.spec.ts --reporter=line`
26
+ 5. **Batched fix loop** (max 5 attempts) see `sungen-selector-fix` skill for details:
27
+ - Group failures by root cause (same selector, same error type)
28
+ - Fix selectors/test-data for the current batch
29
+ - Recompile, then re-run ONLY the previously-failing tests (max 20 at a time via `--grep`)
30
+ - If the batch passes, pick the next batch of remaining failures
31
+ - Repeat until no failures remain or max attempts reached
32
+ 6. **Final confirmation** — run ALL tests once to ensure no regressions.
33
+ 7. After 5 fix attempts still failing → ask user about direct `.spec.ts` fix.
34
+ 8. Show: pass/fail, attempt count, files changed.
@@ -6,16 +6,29 @@ user-invocable: false
6
6
 
7
7
  ## Playwright Errors → Fix
8
8
 
9
- | Error | Fix in `selectors.yaml` |
9
+ | Error | Fix |
10
10
  |---|---|
11
- | strict mode violation | add `nth`, `exact: true`, or specific `name` |
12
- | Element is not an input | change `type` or `value` |
13
- | Timeout waiting for selector | fix `type`/`value`/`name` to match element |
14
- | toBeVisible Timeout | verify accessible name or use `testid` |
15
- | toHaveText mismatch | fix in `test-data.yaml` |
16
- | Navigation failed | fix page `value` path |
17
- | not a select | set `variant: 'custom'` |
18
- | Frame not found | fix `frame` value |
11
+ | strict mode violation | add `nth`, `exact: true`, or specific `name` in selectors.yaml |
12
+ | Element is not an input | change `type` or `value` in selectors.yaml |
13
+ | Timeout waiting for selector | fix `type`/`value`/`name` to match element in selectors.yaml |
14
+ | toBeVisible Timeout | verify accessible name or use `testid` in selectors.yaml |
15
+ | toHaveText mismatch | fix expected text in `test-data.yaml` — OR if element is an input (field/textarea/search/dropdown), change Gherkin type so compiler uses `toHaveValue` instead |
16
+ | toHaveValue mismatch | fix expected value in `test-data.yaml` this is for input elements (field, textarea, search, dropdown, slider, date-picker) |
17
+ | toContainText mismatch | fix expected partial text in `test-data.yaml` |
18
+ | Navigation failed | fix page `value` path in selectors.yaml |
19
+ | not a select | set `variant: 'custom'` in selectors.yaml |
20
+ | Frame not found | fix `frame` value in selectors.yaml |
21
+ | dialog was dismissed | alert step is AFTER the trigger — move `click [OK] alert` BEFORE the button click that opens the dialog |
22
+ | page.once('dialog') never fired | no browser dialog appeared — check if the action actually triggers a `window.alert/confirm/prompt`, not a CSS modal |
23
+
24
+ ### Assertion type mismatch (toHaveText vs toHaveValue)
25
+
26
+ Sungen picks the assertion based on element type:
27
+ - **Input types** (`field`, `textarea`, `search`, `dropdown`, `slider`, `date-picker`) → `toHaveValue()`
28
+ - **Text types** (everything else: `message`, `header`, `label`, `row`, etc.) → `toHaveText()`
29
+ - **Partial match** (uses `contains` keyword) → `toContainText()`
30
+
31
+ If you see `toHaveText` failing on an input element, the Gherkin step has the wrong target type. Fix: change the target type in the `.feature` file (e.g., `see [Email] message with {{v}}` → `see [Email] field with {{v}}`).
19
32
 
20
33
  ## Auth Errors → Fix
21
34
 
@@ -4,13 +4,34 @@ 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> <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
+
17
+ ## Keyword → Action Rules
18
+
19
+ ```
20
+ GIVEN → is on
21
+ WHEN → click · fill · select · press · clear · check · uncheck · hover
22
+ [⚠️ wait for — only for Spinner/Modal, minimize usage]
23
+ THEN → see
24
+ AND → inherits from preceding keyword
25
+ ```
26
+
27
+ ## Step Patterns (70 patterns)
8
28
 
9
29
  ### Setup
10
30
 
11
31
  ```
12
32
  User is on [T] page # navigate to page
13
33
  User is on [T] page with {{v}} # navigate with data (e.g., detail page with ID)
34
+ User is on [T] dialog # enter dialog scope
14
35
  User is logged in | is not logged in # auth state
15
36
  ```
16
37
 
@@ -18,31 +39,57 @@ User is logged in | is not logged in # auth state
18
39
 
19
40
  ```
20
41
  User fill [T] field with {{v}} # text input
42
+ User fill [T] textarea with {{v}} # multiline input
43
+ User fill [T] search with {{v}} # search input
44
+ User fill [T] slider with {{v}} # set slider value
45
+ User fill [T] date picker with {{v}} # date input
21
46
  User clear [T] field # clear input
22
47
  User check [T] checkbox # check
48
+ User check [T] toggle # toggle on (same as check)
49
+ User check [T] radio # select radio
23
50
  User uncheck [T] checkbox # uncheck
51
+ User uncheck [T] toggle # toggle off
24
52
  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
53
+ User upload [T] uploader with {{f}} # file upload
27
54
  ```
28
55
 
29
56
  ### Interaction
30
57
 
31
58
  ```
32
- User click [T] button # click
33
- User click [T] button with {{v}} # click with text match
59
+ User click [T] button # click (static element, no value)
60
+ User click [T] row with {{v}} # click dynamic list item (row/item/card/option)
61
+ User click [T] tab # switch tab
62
+ User click [T] column # sort column
63
+ User click [T] breadcrumb # navigate breadcrumb
34
64
  User double click [T] element # double click
35
- User hover [T] icon # hover
65
+ User hover [T] icon # hover (must have see/click after)
66
+ User hover [T] row # hover row for hidden actions
36
67
  User drag [T] to [T2] # drag and drop
37
68
  User expand [T] row # expand (aria-expanded)
38
69
  User collapse [T] row # collapse (aria-expanded)
39
70
  ```
40
71
 
72
+ #### click + with {{Value}} rule
73
+
74
+ - **NO value** for static elements: `button`, `link`, `icon`, `tab`, `toggle`
75
+ - **WITH value** only for dynamic lists: `row`, `item`, `card`, `option`
76
+
77
+ ### Browser Alert (system dialog)
78
+
79
+ ```
80
+ User click [OK] alert # accept (OK/Accept/Yes/Confirm)
81
+ User click [Cancel] alert # dismiss (Cancel/Dismiss/No)
82
+ User fill [T] alert with {{v}} # fill prompt + accept
83
+ User see [message text] alert # assert dialog message
84
+ ```
85
+
86
+ > Alert steps must appear BEFORE the action that triggers the dialog.
87
+
41
88
  ### Keyboard
42
89
 
43
90
  ```
44
- User press Escape key # global key press
45
- User press Enter on [T] field # key on element
91
+ User press [Escape] key # global key press
92
+ User press [Enter] on [T] field # key on element
46
93
  ```
47
94
 
48
95
  ### Wait
@@ -53,26 +100,51 @@ User wait for [T] dialog # wait for element
53
100
  User wait for [T] dialog is STATE # wait for state
54
101
  User wait for [T] dialog with {{v}} # wait for element with text
55
102
  User wait for [T] page # wait for navigation
103
+ User wait for [T] message # wait for toast/feedback
104
+ User wait for [T] button # wait for button to appear
56
105
  ```
57
106
 
58
107
  ### Scroll & Frame
59
108
 
60
109
  ```
61
110
  User scroll to [T] section # scroll into view
62
- User switch to [T] frame # enter/exit iframe
111
+ User switch to [T] frame # enter iframe
112
+ User switch to [main] frame # exit iframe
63
113
  ```
64
114
 
65
- ### Assertions
115
+ ### Assertions (6 verify patterns)
66
116
 
67
117
  ```
68
- User see [T] page # URL assertion
69
- User see [T] heading # visibility
70
- User see [T] heading with {{v}} # visibility + text
118
+ # 1. Visibility
119
+ User see [T] message # visible (default)
120
+ User see [T] modal is hidden # hidden
121
+
122
+ # 2. Text Content (exact full match — toHaveText)
123
+ User see [T] message with {{v}} # exact text match
124
+ User see [T] header with {{v}} # heading text
125
+ User see [T] label with {{v}} # label text
126
+
127
+ # 3. Partial Text Match (toContainText)
71
128
  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
129
+
130
+ # 4. Input Value (toHaveValue)
131
+ User see [T] field with {{v}} # input value
132
+ User see [T] dropdown with {{v}} # selected value
133
+ User see [T] date picker with {{v}} # date value
134
+ User see [T] search with {{v}} # search input value
135
+ User see [T] slider with {{v}} # slider value
136
+
137
+ # 5. Component State
138
+ User see [T] button is disabled # state assertion
139
+ User see [T] checkbox is checked # checked state
140
+ User see [T] toggle is unchecked # unchecked state
141
+ User see [T] dialog with {{v}} is hidden # text + state combined
142
+
143
+ # 6. Count
144
+ User see [T] row with {{count}} # element count
145
+
146
+ # 7. Page Context
147
+ User see [T] page # URL assertion
76
148
  ```
77
149
 
78
150
  ### Table
@@ -94,12 +166,45 @@ User click [Act] in [Table] table row with {{f}} # action in row
94
166
 
95
167
  ### Element Types
96
168
 
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`
169
+ | Group | Types |
170
+ |---|---|
171
+ | **Context** | `page` `dialog` `modal` `drawer` `tab` `alert` `overlay` `step` |
172
+ | **Input** | `field` `textarea` `search` `dropdown` `option` `checkbox` `radio` `toggle` `uploader` `slider` `date-picker` |
173
+ | **Trigger** | `button` `link` `icon` `menuitem` `tag` |
174
+ | **Data** | `table` `row` `column` `cell` `list` `item` `card` `section` |
175
+ | **Feedback** | `message` `header` `label` `text` `tooltip` `badge` `breadcrumb` `image` |
176
+ | **System** | `key` `frame` `spinner` `progressbar` |
177
+
178
+ ### Auto-infer (no YAML entry needed)
179
+
180
+ | Gherkin | Playwright locator |
181
+ |---|---|
182
+ | `[Submit] button` | `getByRole('button', { name: 'Submit' })` |
183
+ | `[Home] link` | `getByRole('link', { name: 'Home' })` |
184
+ | `[Welcome] heading` / `header` | `getByRole('heading', { name: 'Welcome' })` |
185
+ | `[Email] field` | `getByPlaceholder('Email')` |
186
+ | `[Success] text` / `message` / `label` | `getByText('Success')` |
187
+ | `[Terms] checkbox` | `getByRole('checkbox', { name: 'Terms' })` |
188
+ | `[Male] radio` | `getByRole('radio', { name: 'Male' })` |
189
+ | `[Global] search` | `getByRole('searchbox', { name: 'Global' })` |
190
+ | `[Vietnam] option` | `getByRole('option', { name: 'Vietnam' })` |
191
+ | `[Price] slider` | `getByRole('slider', { name: 'Price' })` |
192
+ | `[Notification] toggle` | `getByRole('switch', { name: 'Notification' })` |
193
+ | `[Profile] tab` | `getByRole('tab', { name: 'Profile' })` |
194
+ | `[Orders] table` | `getByRole('table', { name: 'Orders' })` |
195
+ | `[Products] list` | `getByRole('list', { name: 'Products' })` |
196
+ | `[Name] column` | `getByRole('columnheader', { name: 'Name' })` |
197
+ | `[Confirm] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'Confirm' })` |
98
198
 
99
199
  ## YAML Keys
100
200
 
101
201
  `[Reference]` → **lowercase, keep Unicode**: `[Search Content]` → `search content:`, `[Thời gian]` → `thời gian:`
102
202
 
203
+ - Keys use **spaces** (not dots) as word separators
204
+ - Same label, different element types → add `--type` suffix
205
+ - Same label, nth occurrence → add `--N` suffix
206
+ - Target Name > 30 chars → shorten to 1–3 meaningful words
207
+
103
208
  ## Selectors (priority order)
104
209
 
105
210
  | type | value | name | use |
@@ -120,8 +225,30 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
120
225
 
121
226
  | Tag | Effect |
122
227
  |---|---|
228
+ | `@auto` | Standard scenario, ready for automation |
229
+ | `@manual` | Skip in generation |
230
+ | `@smoke` / `@regression` | Test suite grouping |
123
231
  | `@auth:role` | Use auth storage state for role |
124
232
  | `@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 |
233
+ | `@steps:name` | Define reusable step block (base scenario) |
234
+ | `@extend:name` | Prepend Given→When from @steps block (skip Then) |
235
+
236
+ ### @extend behavior
237
+
238
+ - Tool executes **only Given→When** of `@steps` scenario (skips Then)
239
+ - The `Given` in `@extend` scenario is the **entry assertion** (confirms state after base steps)
240
+ - If `@steps` scenario fails, `@extend` scenario is **skipped**
241
+ - Name format: `snake_case` or `kebab-case` with module prefix: `@steps:kudos__open_modal`
242
+
243
+ ## Common Syntax Errors
244
+
245
+ | Error | Wrong | Correct |
246
+ |---|---|---|
247
+ | Wrong keyword | `Given User click [T] button` | `When User click [T] button` |
248
+ | Wrong action for type | `When User click [T] checkbox` | `When User check [T] checkbox` |
249
+ | press wrong target | `When User press [Submit] button` | `When User press [Enter] key` |
250
+ | uncheck radio | `When User uncheck [Male] radio` | `When User check [Female] radio` |
251
+ | Hardcode data | `with {{admin@mail.com}}` | `with {{invalid_email}}` |
252
+ | Missing `is` for state | `with {{text}} hidden` | `with {{text}} is hidden` |
253
+ | State as value | `with {{disabled}}` | `is disabled` |
254
+ | Missing target type | `fill [email] with {{v}}` | `fill [email] field with {{v}}` |