@sun-asterisk/sungen 2.0.3 → 2.1.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 (47) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/commands/init.d.ts.map +1 -1
  3. package/dist/cli/commands/init.js +3 -2
  4. package/dist/cli/commands/init.js.map +1 -1
  5. package/dist/cli/index.js +1 -1
  6. package/dist/orchestrator/project-initializer.d.ts +3 -6
  7. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  8. package/dist/orchestrator/project-initializer.js +62 -58
  9. package/dist/orchestrator/project-initializer.js.map +1 -1
  10. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +42 -0
  11. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +60 -0
  12. package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +59 -0
  13. package/dist/orchestrator/templates/ai-instructions/claude-config.md +90 -0
  14. package/dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +27 -0
  15. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +123 -0
  16. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +94 -0
  17. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +41 -0
  18. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +59 -0
  19. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +58 -0
  20. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +90 -0
  21. package/dist/orchestrator/templates/ai-instructions/copilot-skill-error-mapping.md +27 -0
  22. package/dist/orchestrator/templates/ai-instructions/copilot-skill-gherkin-syntax.md +123 -0
  23. package/dist/orchestrator/templates/ai-instructions/copilot-skill-selector-keys.md +94 -0
  24. package/dist/orchestrator/templates/readme.md +42 -38
  25. package/docs/gherkin standards/gherkin-core-standard.md +141 -90
  26. package/docs/gherkin standards/gherkin-core-standard.vi.md +264 -54
  27. package/package.json +2 -2
  28. package/src/cli/commands/init.ts +3 -2
  29. package/src/cli/index.ts +1 -1
  30. package/src/orchestrator/project-initializer.ts +74 -58
  31. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +42 -0
  32. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +60 -0
  33. package/src/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +59 -0
  34. package/src/orchestrator/templates/ai-instructions/claude-config.md +90 -0
  35. package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +27 -0
  36. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +123 -0
  37. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +94 -0
  38. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +41 -0
  39. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +59 -0
  40. package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +58 -0
  41. package/src/orchestrator/templates/ai-instructions/copilot-config.md +90 -0
  42. package/src/orchestrator/templates/ai-instructions/copilot-skill-error-mapping.md +27 -0
  43. package/src/orchestrator/templates/ai-instructions/copilot-skill-gherkin-syntax.md +123 -0
  44. package/src/orchestrator/templates/ai-instructions/copilot-skill-selector-keys.md +94 -0
  45. package/src/orchestrator/templates/readme.md +42 -38
  46. package/dist/orchestrator/templates/ai-rules.md +0 -189
  47. package/src/orchestrator/templates/ai-rules.md +0 -189
@@ -5,6 +5,7 @@
5
5
 
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
+ import { execSync } from 'child_process';
8
9
 
9
10
  export class ProjectInitializer {
10
11
  private baseCwd: string;
@@ -12,7 +13,7 @@ export class ProjectInitializer {
12
13
  private createdItems: string[] = [];
13
14
  private skippedItems: string[] = [];
14
15
 
15
- constructor() {
16
+ constructor(private baseUrl: string) {
16
17
  this.baseCwd = process.cwd();
17
18
  this.cwd = this.baseCwd;
18
19
  }
@@ -37,6 +38,9 @@ export class ProjectInitializer {
37
38
  // Create directories
38
39
  this.createDirectories();
39
40
 
41
+ // Ensure package.json and install Playwright
42
+ await this.setupDependencies();
43
+
40
44
  // Create playwright config if doesn't exist
41
45
  this.createPlaywrightConfig();
42
46
 
@@ -99,7 +103,8 @@ export class ProjectInitializer {
99
103
  return;
100
104
  }
101
105
 
102
- const configContent = this.getPlaywrightConfigTemplate();
106
+ const configContent = this.getPlaywrightConfigTemplate()
107
+ .replace('https://example.com', this.baseUrl);
103
108
  fs.writeFileSync(configPath, configContent, 'utf-8');
104
109
  this.createdItems.push('playwright.config.ts');
105
110
  }
@@ -174,9 +179,6 @@ export class ProjectInitializer {
174
179
  });
175
180
  }
176
181
 
177
- // Check for Playwright installation
178
- this.checkDependencies();
179
-
180
182
  console.log('\nNext steps:');
181
183
  let stepIndex = 1;
182
184
  if (projectName) {
@@ -192,48 +194,54 @@ export class ProjectInitializer {
192
194
  * Create AI rules files for GitHub Copilot and Claude Code
193
195
  */
194
196
  private createAIRules(): void {
195
- const rulesContent = this.getAIRulesContent();
196
-
197
- // GitHub Copilot: .github/copilot-instructions.md
198
- const githubDir = path.join(this.cwd, '.github');
199
- const copilotPath = path.join(githubDir, 'copilot-instructions.md');
200
- if (!fs.existsSync(copilotPath)) {
201
- if (!fs.existsSync(githubDir)) {
202
- fs.mkdirSync(githubDir, { recursive: true });
203
- }
204
- fs.writeFileSync(copilotPath, rulesContent, 'utf-8');
205
- this.createdItems.push('.github/copilot-instructions.md');
206
- } else {
207
- this.skippedItems.push('.github/copilot-instructions.md');
208
- }
197
+ const aiTemplateDir = path.join(__dirname, 'templates', 'ai-instructions');
198
+
199
+ // File mapping: [templateFile, outputPath]
200
+ const fileMapping: [string, string][] = [
201
+ // Config
202
+ ['claude-config.md', 'CLAUDE.md'],
203
+ ['copilot-config.md', '.github/copilot-instructions.md'],
204
+
205
+ // Commands — Claude Code
206
+ ['claude-cmd-add-screen.md', '.claude/commands/sungen/add-screen.md'],
207
+ ['claude-cmd-make-tc.md', '.claude/commands/sungen/make-tc.md'],
208
+ ['claude-cmd-make-test.md', '.claude/commands/sungen/make-test.md'],
209
+
210
+ // Commands — GitHub Copilot
211
+ ['copilot-cmd-add-screen.md', '.github/prompts/sungen-add-screen.prompt.md'],
212
+ ['copilot-cmd-make-tc.md', '.github/prompts/sungen-make-tc.prompt.md'],
213
+ ['copilot-cmd-make-test.md', '.github/prompts/sungen-make-test.prompt.md'],
214
+
215
+ // Skills — Claude Code
216
+ ['claude-skill-gherkin-syntax.md', '.claude/skills/sungen-gherkin-syntax/SKILL.md'],
217
+ ['claude-skill-selector-keys.md', '.claude/skills/sungen-selector-keys/SKILL.md'],
218
+ ['claude-skill-error-mapping.md', '.claude/skills/sungen-error-mapping/SKILL.md'],
219
+
220
+ // Skills — GitHub Copilot
221
+ ['copilot-skill-gherkin-syntax.md', '.github/prompts/sungen-gherkin-syntax.prompt.md'],
222
+ ['copilot-skill-selector-keys.md', '.github/prompts/sungen-selector-keys.prompt.md'],
223
+ ['copilot-skill-error-mapping.md', '.github/prompts/sungen-error-mapping.prompt.md'],
224
+ ];
209
225
 
210
- // Claude Code: CLAUDE.md
211
- const claudePath = path.join(this.cwd, 'CLAUDE.md');
212
- if (!fs.existsSync(claudePath)) {
213
- fs.writeFileSync(claudePath, rulesContent, 'utf-8');
214
- this.createdItems.push('CLAUDE.md');
215
- } else {
216
- this.skippedItems.push('CLAUDE.md');
217
- }
226
+ for (const [templateFile, outputRelPath] of fileMapping) {
227
+ const outputPath = path.join(this.cwd, outputRelPath);
218
228
 
219
- // Gherkin Dictionary: docs/gherkin-dictionary.md
220
- const docsDir = path.join(this.cwd, 'docs');
221
- const dictPath = path.join(docsDir, 'gherkin-dictionary.md');
222
- if (!fs.existsSync(dictPath)) {
223
- // Copy from sungen package if available, otherwise generate stub
224
- const packageDictPath = path.join(__dirname, '..', '..', 'docs', 'gherkin-dictionary.md');
225
- if (!fs.existsSync(docsDir)) {
226
- fs.mkdirSync(docsDir, { recursive: true });
229
+ if (fs.existsSync(outputPath)) {
230
+ this.skippedItems.push(outputRelPath);
231
+ continue;
227
232
  }
228
- if (fs.existsSync(packageDictPath)) {
229
- fs.copyFileSync(packageDictPath, dictPath);
230
- } else {
231
- fs.writeFileSync(dictPath, '# Sungen Gherkin Dictionary\n\nSee https://github.com/sun-asterisk/sungen for the full dictionary.\n', 'utf-8');
233
+
234
+ const outputDir = path.dirname(outputPath);
235
+ if (!fs.existsSync(outputDir)) {
236
+ fs.mkdirSync(outputDir, { recursive: true });
232
237
  }
233
- this.createdItems.push('docs/gherkin-dictionary.md');
234
- } else {
235
- this.skippedItems.push('docs/gherkin-dictionary.md');
238
+
239
+ const templatePath = path.join(aiTemplateDir, templateFile);
240
+ const content = fs.readFileSync(templatePath, 'utf-8');
241
+ fs.writeFileSync(outputPath, content, 'utf-8');
242
+ this.createdItems.push(outputRelPath);
236
243
  }
244
+
237
245
  }
238
246
 
239
247
  /**
@@ -244,30 +252,38 @@ export class ProjectInitializer {
244
252
  return fs.readFileSync(templatePath, 'utf-8');
245
253
  }
246
254
 
247
- /**
248
- * Get AI rules content (shared between Copilot and Claude)
249
- */
250
- private getAIRulesContent(): string {
251
- return this.readTemplate('ai-rules.md');
252
- }
253
-
254
255
  /**
255
256
  * Check for required dependencies
256
257
  */
257
- private checkDependencies(): void {
258
+ private async setupDependencies(): Promise<void> {
259
+ const packageJsonPath = path.join(this.cwd, 'package.json');
260
+ const execOpts = { cwd: this.cwd, stdio: 'inherit' as const };
261
+
262
+ // Initialize package.json if it doesn't exist
263
+ if (!fs.existsSync(packageJsonPath)) {
264
+ console.log('📦 No package.json found. Initializing...\n');
265
+ execSync('npm init -y', execOpts);
266
+ this.createdItems.push('package.json');
267
+ }
268
+
269
+ // Check if @playwright/test is already installed
258
270
  try {
259
- const packageJsonPath = path.join(this.cwd, 'package.json');
260
271
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
261
272
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
262
-
263
- if (!deps['@playwright/test']) {
264
- console.log('\n⚠️ Playwright not detected. Install with:');
265
- console.log(' npm install -D @playwright/test');
266
- console.log(' npx playwright install');
273
+ if (deps['@playwright/test']) {
274
+ console.log('@playwright/test already installed\n');
275
+ return;
267
276
  }
268
- } catch (error) {
269
- // Ignore if can't read package.json
277
+ } catch {
278
+ // package.json just created, proceed with install
270
279
  }
280
+
281
+ // Install Playwright
282
+ console.log('📦 Installing @playwright/test...\n');
283
+ execSync('npm install -D @playwright/test', execOpts);
284
+
285
+ console.log('\n🎭 Installing Playwright browsers...\n');
286
+ execSync('npx playwright install', execOpts);
271
287
  }
272
288
 
273
289
  /**
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: add-screen
3
+ description: 'Add a new Sungen screen — scaffolds directories and delegates to make-tc for test case creation'
4
+ argument-hint: [screen-name] [url-path]
5
+ allowed-tools: Read, Grep, Bash, Glob
6
+ ---
7
+
8
+ You are adding a new Sungen screen for test generation.
9
+
10
+ ## Parameters
11
+
12
+ Parse from `$ARGUMENTS`:
13
+ - **screen** — screen name (e.g., `login`, `dashboard`, `settings`)
14
+ - **path** — URL path (e.g., `/login`, `/dashboard`, `/settings`)
15
+
16
+ If **screen** is missing, ask: "What is the screen name? (e.g., `login`, `dashboard`)"
17
+ If **path** is missing, ask: "What is the URL path? (e.g., `/login`, `/dashboard`)"
18
+
19
+ ## Steps
20
+
21
+ ### 1. Scaffold the screen
22
+
23
+ Run:
24
+ ```bash
25
+ sungen add --screen <screen> --path <path>
26
+ ```
27
+
28
+ ### 2. Create test cases
29
+
30
+ Ask the user: "Would you like to create test cases now?"
31
+
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)
36
+
37
+ ### 3. Confirm
38
+
39
+ Tell the user what was created and next steps:
40
+ - If the page requires authentication before exploring via browser, read `baseURL` from `playwright.config.ts` and tell the user to manually run: `sungen makeauth <role> --url <baseURL>` (e.g., `sungen makeauth admin --url http://localhost:3000`). **Do NOT execute this command yourself.**
41
+ - Edit the generated files as needed
42
+ - Run `sungen generate --screen <screen>` to compile to Playwright `.spec.ts`
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: make-tc
3
+ description: 'Create test cases for a Sungen screen — gathers viewpoints, explores live page or static designs, generates feature/selectors/test-data files'
4
+ argument-hint: [screen-name]
5
+ allowed-tools: Read, Grep, Bash, Glob
6
+ ---
7
+
8
+ ## Role
9
+
10
+ You are a **Senior QA Engineer** specialized in test case design. You structure test cases by viewpoint categories and translate UI into Gherkin test cases following the `sungen-gherkin-syntax` and `sungen-selector-keys` skills.
11
+
12
+ ## Parameters
13
+
14
+ Parse from `$ARGUMENTS`:
15
+ - **screen** — screen name (e.g., `login`, `dashboard`)
16
+
17
+ If missing, ask the user.
18
+
19
+ ## Steps
20
+
21
+ ### 1. Verify screen exists
22
+
23
+ Check `qa/screens/<screen>/` exists. If not, tell user to run `/sungen:add-screen` first.
24
+
25
+ ### 2. Determine source mode
26
+
27
+ Ask: "Do you have a **live page** or **static designs** (screenshots, Figma, images)?"
28
+
29
+ **Live page →** explore via browser (see CLAUDE.md for Playwright MCP rules). If auth needed, check `specs/.auth/<role>.json` exists — if not, read `baseURL` from `playwright.config.ts` and tell the user to manually run: `sungen makeauth <role> --url <baseURL>` (e.g., `sungen makeauth admin --url http://localhost:3000`). **Do NOT execute `sungen makeauth` yourself.** Wait for the user to confirm auth is ready before proceeding.
30
+
31
+ **Static designs →** ask user to provide screenshot paths, Figma exports, or UI descriptions. Note: selectors will be best-guess until live page is available.
32
+
33
+ Present discovered elements to user, then proceed.
34
+
35
+ ### 3. Gather test viewpoints
36
+
37
+ | VP Category | Description |
38
+ |---|---|
39
+ | **UI/UX** | Default screen appearance, static elements, default states |
40
+ | **Validation** | Field/form validation, error messages |
41
+ | **Logic** | Business logic, happy paths, redirects |
42
+ | **Security** | Auth guards, permission checks |
43
+
44
+ For each viewpoint, gather: **UI Target**, **Test Viewpoint**, **Expected Result**.
45
+
46
+ User can provide all at once as a table:
47
+ ```
48
+ | VP Category | UI Target | Test Viewpoint | Expected Result |
49
+ ```
50
+
51
+ ### 4. Generate files
52
+
53
+ Generate the 3 files following `sungen-gherkin-syntax` and `sungen-selector-keys` skill rules:
54
+ - `qa/screens/<screen>/features/<screen>.feature` — one Scenario per viewpoint
55
+ - `qa/screens/<screen>/selectors/<screen>.yaml`
56
+ - `qa/screens/<screen>/test-data/<screen>.yaml`
57
+
58
+ ### 5. Confirm
59
+
60
+ Show what was generated. Next: `sungen generate --screen <screen>`
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: make-test
3
+ description: 'Compile and run Playwright tests for a Sungen screen — auto-fixes selectors on failure, falls back to AI .spec.ts fix after 5 attempts'
4
+ argument-hint: [screen-name]
5
+ allowed-tools: Read, Grep, Bash, Glob, Edit
6
+ ---
7
+
8
+ ## Role
9
+
10
+ You are a **Senior Developer** specialized in Playwright test debugging. You diagnose test failures, fix selectors/test-data, and patch `.spec.ts` when needed. Use the `sungen-error-mapping` and `sungen-selector-keys` skills for error diagnosis and key fixes.
11
+
12
+ ## Parameters
13
+
14
+ Parse from `$ARGUMENTS`:
15
+ - **screen** — screen name (e.g., `login`, `dashboard`)
16
+
17
+ If missing, ask the user.
18
+
19
+ ## Steps
20
+
21
+ ### 1. Verify screen exists
22
+
23
+ Check `qa/screens/<screen>/` has all 3 source files. If not, tell user to run `/sungen:add-screen` and `/sungen:make-tc` first.
24
+
25
+ ### 2. Compile
26
+
27
+ ```bash
28
+ sungen generate --screen <screen>
29
+ ```
30
+
31
+ If fails, fix source files per `sungen-error-mapping` skill and retry.
32
+
33
+ ### 3. Run tests
34
+
35
+ ```bash
36
+ npx playwright test specs/screens/<screen>/<screen>.spec.ts
37
+ ```
38
+
39
+ If pass → Step 5. If fail → Step 4.
40
+
41
+ ### 4. Fix and retry (max 5 attempts)
42
+
43
+ Per attempt:
44
+ 1. Read Playwright error output
45
+ 2. Map error to fix using `sungen-error-mapping` skill
46
+ 3. Fix `selectors.yaml` or `test-data.yaml`
47
+ 4. Recompile: `sungen generate --screen <screen>`
48
+ 5. Retest
49
+
50
+ ### 5. Fallback — AI fix .spec.ts
51
+
52
+ After 5 failed attempts, ask user:
53
+ > Tests still failing. Would you like me to directly fix the `.spec.ts` file?
54
+
55
+ If yes: read `.spec.ts`, fix locators/assertions, mark with `// AI-fixed: <reason>`
56
+
57
+ ### 6. Confirm
58
+
59
+ Show: pass/fail, attempt count, files changed.
@@ -0,0 +1,90 @@
1
+ # Sungen AI Rules
2
+
3
+ You generate 3 files for sungen — a Gherkin compiler that produces Playwright tests.
4
+ **You do NOT write Playwright code.** You only write `.feature`, `selectors.yaml`, and `test-data.yaml`.
5
+
6
+ For Gherkin syntax, selector types, and YAML rules, the `sungen-gherkin-syntax` skill is auto-loaded when needed.
7
+ For error diagnosis, the `sungen-error-mapping` skill is auto-loaded when needed.
8
+
9
+ ## Complete Example
10
+
11
+ Given a login page, here are the 3 files you generate:
12
+
13
+ **qa/screens/login/features/login.feature**
14
+ ```gherkin
15
+ @auth:admin
16
+ Feature: Login Screen
17
+
18
+ Scenario: Successful login
19
+ Given User is on [login] page
20
+ When User fill [Email] field with {{email}}
21
+ And User fill [Password] field with {{password}}
22
+ And User click [Submit] button
23
+ Then User see [Welcome] heading with {{welcome_text}}
24
+ And User see [Dashboard] link is visible
25
+ ```
26
+
27
+ **qa/screens/login/selectors/login.yaml**
28
+ ```yaml
29
+ login:
30
+ type: 'page'
31
+ value: '/login'
32
+
33
+ email:
34
+ type: 'placeholder'
35
+ value: 'Enter your email'
36
+
37
+ password:
38
+ type: 'placeholder'
39
+ value: 'Enter your password'
40
+
41
+ submit:
42
+ type: 'role'
43
+ value: 'button'
44
+ name: 'Submit'
45
+
46
+ welcome:
47
+ type: 'role'
48
+ value: 'heading'
49
+ name: 'Welcome'
50
+
51
+ dashboard:
52
+ type: 'role'
53
+ value: 'link'
54
+ name: 'Dashboard'
55
+ ```
56
+
57
+ **qa/screens/login/test-data/login.yaml**
58
+ ```yaml
59
+ email: 'admin@example.com'
60
+ password: 'password123'
61
+ welcome_text: 'Welcome back'
62
+ ```
63
+
64
+ ## Using Playwright MCP to explore pages
65
+
66
+ When exploring a page to generate test files:
67
+ 1. Read `playwright.config.ts` for `baseURL`
68
+ 2. Use `browser_navigate` to open `baseURL + /path`
69
+ 3. Use `browser_snapshot` to see all elements
70
+ 4. Generate the 3 files from the snapshot
71
+
72
+ **NEVER use `browser_run_code`.** It fails with `require is not defined`.
73
+ Only use: `browser_navigate`, `browser_snapshot`, `browser_click`, `browser_fill_form`, `browser_evaluate`.
74
+
75
+ To browse authenticated pages via MCP:
76
+ 1. Check if `specs/.auth/<role>.json` exists
77
+ 2. If not, read `baseURL` from `playwright.config.ts` and tell the user to manually run: `sungen makeauth <role> --url <baseURL>`. **Do NOT execute `sungen makeauth` yourself.** Wait for user confirmation.
78
+ 3. Read `specs/.auth/<role>.json`
79
+ 4. `browser_navigate` to the page
80
+ 5. `browser_evaluate` to inject localStorage and cookies from the JSON
81
+ 6. `browser_navigate` again to reload with auth
82
+
83
+ ## Commands
84
+
85
+ ```bash
86
+ sungen add --screen <name> --path <url-path> # Create screen
87
+ sungen generate --screen <name> # Compile to .spec.ts
88
+ sungen generate --all # Compile all
89
+ sungen makeauth <role> # Capture auth state
90
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: sungen-error-mapping
3
+ description: 'Playwright and Sungen error to fix mapping. Auto-loaded when running or debugging tests.'
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## Playwright Errors → Fix
8
+
9
+ | Error | Fix in `selectors.yaml` |
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 |
19
+
20
+ ## Sungen Errors → Fix
21
+
22
+ | Error | Fix |
23
+ |---|---|
24
+ | Unknown step pattern | rewrite `.feature` step to match supported pattern |
25
+ | Missing selector | add key to `selectors.yaml` |
26
+ | Missing variable | add key to `test-data.yaml` |
27
+ | Invalid selector type | use: role/testid/placeholder/label/text/locator/page/upload/frame |
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: sungen-gherkin-syntax
3
+ description: 'Sungen Gherkin patterns, selector types, and YAML key rules. Auto-loaded when writing .feature, selectors.yaml, or test-data.yaml.'
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## Step Patterns (58 patterns)
8
+
9
+ ### Setup
10
+
11
+ ```
12
+ User is on [T] page # navigate to page
13
+ User navigate to [T] page with {{v}} # navigate with data
14
+ User is logged in | is not logged in # auth state
15
+ ```
16
+
17
+ ### Form
18
+
19
+ ```
20
+ User fill [T] field with {{v}} # text input
21
+ User clear [T] field # clear input
22
+ User check [T] checkbox # check
23
+ User uncheck [T] checkbox # uncheck
24
+ User select [T] dropdown with {{v}} # select option
25
+ User upload [T] file with {{f}} # file upload
26
+ ```
27
+
28
+ ### Interaction
29
+
30
+ ```
31
+ User click [T] button # click
32
+ User click [T] button with {{v}} # click with text match
33
+ User double click [T] element # double click
34
+ User hover [T] icon # hover
35
+ ```
36
+
37
+ ### Keyboard
38
+
39
+ ```
40
+ User press Escape key # global key press
41
+ User press Enter on [T] field # key on element
42
+ ```
43
+
44
+ ### Wait
45
+
46
+ ```
47
+ User wait for N seconds # wait timeout
48
+ User wait for [T] dialog # wait for element
49
+ User wait for [T] dialog is STATE # wait for state
50
+ User wait for [T] dialog with {{v}} # wait for element with text
51
+ User wait for [T] page # wait for navigation
52
+ ```
53
+
54
+ ### Scroll & Frame
55
+
56
+ ```
57
+ User scroll to [T] section # scroll into view
58
+ User switch to [T] frame # enter/exit iframe
59
+ ```
60
+
61
+ ### Assertions
62
+
63
+ ```
64
+ User see [T] page # URL assertion
65
+ User see [T] heading # visibility
66
+ User see [T] heading with {{v}} # visibility + text
67
+ User see [T] text contains {{v}} # partial text match
68
+ User see [T] text has text {{v}} # exact text match
69
+ User see [T] button is STATE # state assertion
70
+ User see [T] dialog with {{v}} is STATE # text + state
71
+ User see {{v}} # see data text
72
+ ```
73
+
74
+ ### Table
75
+
76
+ ```
77
+ User see [Table] table has row with {{f}} # row exists
78
+ User see [Table] table has no row with {{f}} # row not exists
79
+ User see [Table] table has {{count}} rows # row count
80
+ User see [Table] table has [Col] column # column exists
81
+ User see [Table] table is empty # empty table
82
+ User see [Table] table row with {{f}} has [Col] with {{v}} # cell by filter
83
+ User see [Table] table row 1 [Col] cell with {{v}} # cell by index
84
+ User click [Act] in [Table] table row with {{f}} # action in row
85
+ ```
86
+
87
+ ### States
88
+
89
+ `hidden` `visible` `disabled` `enabled` `checked` `unchecked` `focused` `empty`
90
+
91
+ ### Element Types
92
+
93
+ `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`
94
+
95
+ ## YAML Keys
96
+
97
+ `[Reference]` → **lowercase, spaces→dots**: `[Search Content]` → `search.content:`
98
+
99
+ ## Selectors (priority order)
100
+
101
+ | type | value | name | use |
102
+ |---|---|---|---|
103
+ | `testid` | data-testid | — | when exists |
104
+ | `role` | button/heading/link… | accessible name | interactive elements |
105
+ | `placeholder` | placeholder text | — | inputs |
106
+ | `label` | label text | — | labeled inputs |
107
+ | `text` | — | — | static text |
108
+ | `locator` | CSS selector | — | last resort |
109
+ | `page` | relative URL | — | navigation |
110
+ | `upload` | — | — | file inputs |
111
+ | `frame` | iframe selector | — | iframes |
112
+
113
+ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `columns`
114
+
115
+ ## Tags
116
+
117
+ | Tag | Effect |
118
+ |---|---|
119
+ | `@auth:role` | Use auth storage state for role |
120
+ | `@no-auth` | Disable inherited auth |
121
+ | `@steps:name` | Define reusable step block |
122
+ | `@extend:name` | Prepend steps from @steps block |
123
+ | `@manual` | Skip in generation |