@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
@@ -47,6 +47,8 @@ export class ScreenManager {
47
47
  const featuresDir = path.join(screenDir, 'features');
48
48
  const selectorsDir = path.join(screenDir, 'selectors');
49
49
  const testDataDir = path.join(screenDir, 'test-data');
50
+ const requirementsDir = path.join(screenDir, 'requirements');
51
+ const requirementsUiDir = path.join(requirementsDir, 'ui');
50
52
 
51
53
  // File paths
52
54
  const featurePath = path.join(featuresDir, `${filename}.feature`);
@@ -66,6 +68,7 @@ export class ScreenManager {
66
68
  fs.mkdirSync(featuresDir, { recursive: true });
67
69
  fs.mkdirSync(selectorsDir, { recursive: true });
68
70
  fs.mkdirSync(testDataDir, { recursive: true });
71
+ fs.mkdirSync(requirementsUiDir, { recursive: true });
69
72
  } catch (error) {
70
73
  console.error(`Error: Failed to create directories`);
71
74
  console.error(` ${error instanceof Error ? error.message : String(error)}`);
@@ -111,15 +114,27 @@ export class ScreenManager {
111
114
  ].join('\n'), 'utf-8');
112
115
  }
113
116
 
117
+ // Generate requirements spec.md (only on first screen creation)
118
+ const specPath = path.join(requirementsDir, 'spec.md');
119
+ if (!fs.existsSync(specPath)) {
120
+ fs.writeFileSync(specPath, this.generateSpecTemplate(options, screenName), 'utf-8');
121
+ }
122
+
114
123
  // Display success
115
124
  console.log(`Created files:`);
116
125
  console.log(` ${path.relative(this.cwd, featurePath)}`);
117
126
  console.log(` ${path.relative(this.cwd, selectorPath)}`);
118
- console.log(` ${path.relative(this.cwd, testDataPath)}\n`);
127
+ console.log(` ${path.relative(this.cwd, testDataPath)}`);
128
+ if (isFirstFile) {
129
+ console.log(` ${path.relative(this.cwd, specPath)}`);
130
+ console.log(` ${path.relative(this.cwd, requirementsUiDir)}/`);
131
+ }
132
+ console.log('');
119
133
 
120
134
  console.log('Next steps:');
121
- console.log(` 1. Use AI (Copilot/Claude) to generate Gherkin + selectors from the live page`);
122
- console.log(` 2. Fill in test-data values`);
135
+ console.log(` 1. Fill requirements/spec.md with screen spec (fields, validation, business rules)`);
136
+ console.log(` Optionally add UI designs to requirements/ui/ (screenshots, mockups)`);
137
+ console.log(` 2. Generate test cases: /sungen:make-tc ${screenName} (or /sungen-make-tc)`);
123
138
  console.log(` 3. Compile: sungen generate --screen ${screenName}`);
124
139
  console.log(` 4. Run: npx playwright test\n`);
125
140
  }
@@ -150,6 +165,60 @@ export class ScreenManager {
150
165
  return this.normalizeScreenName(lastSegment);
151
166
  }
152
167
 
168
+ private generateSpecTemplate(options: ScreenOptions, screenName: string): string {
169
+ const pagePath = options.path || `/${screenName}`;
170
+ return `# ${options.name} Screen Specification
171
+
172
+ ## Overview
173
+ - **URL Path:** ${pagePath}
174
+ - **Auth Required:** no
175
+ - **Platform:** web
176
+
177
+ ## Sections
178
+
179
+ ### Section: [Section Name]
180
+ - **Type:** form | table | list | card | tabs | modal | search | navigation
181
+ - **Description:** [Brief description of this section]
182
+
183
+ #### Fields
184
+ <!-- Remove this table if section has no input fields -->
185
+ | Field | Type | Required | Constraints | Default |
186
+ |-------|------|----------|-------------|---------|
187
+ | [Field Name] | input (text) | yes | max 255 | — |
188
+
189
+ #### Actions
190
+ | Action | Element | Behavior |
191
+ |--------|---------|----------|
192
+ | [Action Name] | button | [What happens on click] |
193
+
194
+ #### Validation Rules
195
+ <!-- Exact error messages help AI generate accurate assertions -->
196
+ | Condition | Error Message |
197
+ |-----------|---------------|
198
+ | Empty required field | "[Exact error message from UI]" |
199
+
200
+ #### States
201
+ | State | Condition | Visual |
202
+ |-------|-----------|--------|
203
+ | Default | Page load | [Default appearance] |
204
+ | Loading | After submit | [Loading indicator] |
205
+ | Error | Validation fail | [Error appearance] |
206
+ | Success | Action complete | [Success behavior] |
207
+
208
+ ## Business Rules
209
+ <!-- Rules that affect test logic: limits, permissions, conditions -->
210
+ - [Rule 1]
211
+
212
+ ## Accessibility
213
+ <!-- Tab order, aria-labels, screen reader behavior -->
214
+ - Tab order: [field1] → [field2] → [submit]
215
+
216
+ ## Notes
217
+ <!-- Edge cases, known issues, environment-specific behavior -->
218
+ - [Note 1]
219
+ `;
220
+ }
221
+
153
222
  private generateFeatureTemplate(options: ScreenOptions, filename: string): string {
154
223
  const screenName = this.normalizeScreenName(options.name);
155
224
  const featurePath = options.path || `/${screenName}`;
@@ -25,19 +25,28 @@ Run:
25
25
  sungen add --screen <screen> --path <path>
26
26
  ```
27
27
 
28
- ### 2. Create test cases
28
+ ### 2. Fill requirements (recommended)
29
+
30
+ Ask the user: "Would you like to fill in `requirements/spec.md` now? This helps generate higher quality test cases."
31
+
32
+ - If yes → open `qa/screens/<screen>/requirements/spec.md` and help the user fill sections, fields, validation rules, business rules, and states.
33
+ - If they have UI designs (screenshots, Figma exports, mockups) → suggest copying them to `requirements/ui/`.
34
+ - If no → proceed to step 3.
35
+
36
+ ### 3. Create test cases
29
37
 
30
38
  Ask the user: "Would you like to create test cases now?"
31
39
 
32
- If yes, delegate to `/sungen:make-tc <screen>` to handle:
33
- - Exploring the live page or analyzing static designs
34
- - Gathering test viewpoints (UI/UX, Validation, Logic, Security)
35
- - Generating the 3 files (feature, selectors, test-data)
40
+ If yes **you MUST use the Skill tool** to invoke `/sungen:make-tc <screen>`. This is critical because `make-tc` auto-loads the `sungen-gherkin-syntax` and `sungen-tc-generation` skills which contain the full Gherkin syntax rules, pattern shapes, viewpoint checklists, and output format. **Do NOT attempt to generate test cases yourself** — always invoke the Skill tool so these skills are properly loaded.
41
+
42
+ ```
43
+ Skill: make-tc
44
+ Args: <screen>
45
+ ```
36
46
 
37
- ### 3. Confirm
47
+ ### 4. Confirm
38
48
 
39
- Tell the user what was created and next steps:
40
- - If the page requires authentication, the user will be asked to log in via the MCP browser during `/sungen:make-tc`
41
- - Edit the generated files as needed
49
+ If the user declined test case creation, tell them next steps:
50
+ - Fill `requirements/spec.md` with screen specs (if not done)
42
51
  - Run `/sungen:make-tc <screen>` to create test cases
43
52
  - Run `/sungen:make-test <screen>` to generate selectors, compile, and run tests
@@ -17,9 +17,16 @@ Parse **screen** from `$ARGUMENTS`. If missing, ask the user.
17
17
 
18
18
  1. Verify `qa/screens/<screen>/` exists. If not → `/sungen:add-screen` first.
19
19
  2. Check if `.feature` file already has scenarios. If yes → use `AskUserQuestion` to ask the update mode (see `sungen-tc-generation` skill for details). If no → fresh creation.
20
- 3. Use `AskUserQuestion` to ask: **Live page** (explore via Playwright MCP) or **Static designs** (screenshots, Figma)? Explore accordingly (see CLAUDE.md for MCP rules).
21
- 4. Follow the `sungen-tc-generation` skill for section identification, viewpoint generation, and output format.
22
- 5. Generate or update `.feature` + `test-data.yaml` following `sungen-gherkin-syntax` and `sungen-tc-generation` skills.
23
- 6. Show summary next: `/sungen:make-test <screen>`
20
+ 3. **Read requirements** check `qa/screens/<screen>/requirements/`:
21
+ - If `spec.md` exists read it as PRIMARY source (sections, fields, validation rules, business rules, states).
22
+ - If `ui/` has images read them for visual context (layout, element positions, states).
23
+ - If `notes.md` existsread for edge cases and additional context.
24
+ - Summarize what you found in requirements and present to the user.
25
+ 4. **Explore page** (supplements requirements, or is primary source if no requirements):
26
+ - Use `AskUserQuestion` to ask: **Live page** (explore via Playwright MCP) or **Static designs** (screenshots, Figma)? Or **Skip** (if requirements are sufficient)?
27
+ - If exploring, verify and supplement requirements — flag any discrepancies found.
28
+ 5. Follow the `sungen-tc-generation` skill for section identification, viewpoint generation, and output format. When requirements exist, use the "Requirements-Driven Generation" strategy.
29
+ 6. Generate or update `.feature` + `test-data.yaml` following `sungen-gherkin-syntax` and `sungen-tc-generation` skills.
30
+ 7. Show summary → next: `/sungen:make-test <screen>`
24
31
 
25
32
  **No selectors.yaml** — selectors are generated during `/sungen:make-test`.
@@ -16,9 +16,14 @@ Parse **screen** from `$ARGUMENTS`. If missing, ask the user.
16
16
  ## Steps
17
17
 
18
18
  1. Verify `qa/screens/<screen>/` has `.feature` + `test-data.yaml`. If not → `/sungen:make-tc` first.
19
- 2. Generate `selectors.yaml` from live page using `sungen-selector-fix` and `sungen-selector-keys` skills.
20
- 3. Compile: `sungen generate --screen <screen>`
21
- 4. Run: `npx playwright test specs/screens/<screen>/<screen>.spec.ts`
22
- 5. If fail fix selectors/test-data per `sungen-selector-fix` + `sungen-error-mapping` skills, retry (max 5).
23
- 6. After 5 fails ask user about direct `.spec.ts` fix.
24
- 7. Show: pass/fail, attempt count, files changed.
19
+ 2. **Generate selectors** explore live page via MCP, build `selectors.yaml` using `sungen-selector-fix` and `sungen-selector-keys` skills.
20
+ 3. **Proactive validation** — verify EVERY selector against the live page using `browser_snapshot` + `browser_evaluate` BEFORE running any test. Fix mismatches immediately. See `sungen-selector-fix` skill "Proactive Selector Validation" section. Target: 80%+ issues fixed before first run.
21
+ 4. **Compile**: `sungen generate --screen <screen>`
22
+ 5. **Batched test run** run tests in batches of 20 via `--grep`:
23
+ `npx playwright test specs/generated/<screen>/*.spec.ts --grep "VP-UI-001|...|VP-UI-020" --reporter=line`
24
+ - If failures in batch → group by root cause, fix, recompile, re-run only failing tests
25
+ - If batch passes → move to next 20 tests
26
+ - Max 5 fix attempts per batch
27
+ 6. **Final confirmation** — run ALL tests once to catch regressions.
28
+ 7. After 5 fix attempts still failing → ask user about direct `.spec.ts` fix.
29
+ 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,35 @@ 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> <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}}` |