@sun-asterisk/sungen 2.2.3 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/cli/commands/update.d.ts +3 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +21 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +2 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +16 -2
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +12 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +12 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.js +12 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +9 -0
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +32 -0
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js +0 -13
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/table-patterns.js +8 -5
- package/dist/generators/test-generator/patterns/table-patterns.js.map +1 -1
- package/dist/orchestrator/ai-rules-updater.d.ts +13 -0
- package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -0
- package/dist/orchestrator/ai-rules-updater.js +159 -0
- package/dist/orchestrator/ai-rules-updater.js.map +1 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +2 -27
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts +1 -0
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +70 -3
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +12 -4
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +9 -11
- package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-review.md +228 -0
- package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +30 -11
- package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +91 -25
- package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +92 -71
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -5
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +13 -4
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +9 -11
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-review.md +228 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +30 -11
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +72 -31
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +92 -72
- package/dist/orchestrator/templates/readme.md +13 -8
- package/package.json +1 -1
- package/src/cli/commands/update.ts +18 -0
- package/src/cli/index.ts +3 -1
- package/src/generators/gherkin-parser/index.ts +19 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +12 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +12 -1
- package/src/generators/test-generator/patterns/assertion-patterns.ts +13 -0
- package/src/generators/test-generator/patterns/index.ts +41 -0
- package/src/generators/test-generator/patterns/interaction-patterns.ts +0 -14
- package/src/generators/test-generator/patterns/table-patterns.ts +8 -5
- package/src/orchestrator/ai-rules-updater.ts +141 -0
- package/src/orchestrator/project-initializer.ts +2 -32
- package/src/orchestrator/screen-manager.ts +72 -3
- package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
- package/src/orchestrator/templates/ai-instructions/claude-cmd-make-tc.md +12 -4
- package/src/orchestrator/templates/ai-instructions/claude-cmd-make-test.md +9 -11
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-review.md +228 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +30 -11
- package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +91 -25
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +92 -71
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -5
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-tc.md +13 -4
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-make-test.md +9 -11
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-review.md +228 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +30 -11
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +72 -31
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +92 -72
- package/src/orchestrator/templates/readme.md +13 -8
- package/docs/gherkin standards/gherkin-core-standard.md +0 -431
- package/docs/gherkin standards/gherkin-core-standard.vi.md +0 -399
- package/docs/gherkin-dictionary.md +0 -1126
- package/docs/makeauth.md +0 -225
|
@@ -203,20 +203,6 @@ export const interactionPatterns: StepPattern[] = [
|
|
|
203
203
|
},
|
|
204
204
|
priority: 8,
|
|
205
205
|
},
|
|
206
|
-
{
|
|
207
|
-
name: 'press-enter',
|
|
208
|
-
matcher: (step: ParsedStep) =>
|
|
209
|
-
step.text.includes('presses') && step.text.includes('Enter') && !!step.selectorRef,
|
|
210
|
-
resolver: (step, context) => {
|
|
211
|
-
const resolved = context.selectorResolver.resolveSelector(step.selectorRef!, undefined, step.elementType, step.nth);
|
|
212
|
-
return {
|
|
213
|
-
templateName: 'press-action',
|
|
214
|
-
data: { ...resolved, key: 'Enter' },
|
|
215
|
-
comment: `Press Enter in ${step.selectorRef}`,
|
|
216
|
-
};
|
|
217
|
-
},
|
|
218
|
-
priority: 9,
|
|
219
|
-
},
|
|
220
206
|
{
|
|
221
207
|
name: 'click-by-data-text',
|
|
222
208
|
matcher: (step: ParsedStep) =>
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
import { StepPattern } from './types';
|
|
7
7
|
|
|
8
8
|
export const tablePatterns: StepPattern[] = [
|
|
9
|
-
// "User see [Users] table
|
|
9
|
+
// "User see [Users] table with {{count}} rows" (preferred)
|
|
10
|
+
// Also accepts: "User see [Users] table has {{count}} rows" (backward compat)
|
|
10
11
|
{
|
|
11
12
|
name: 'table-row-count',
|
|
12
13
|
matcher: (step) => {
|
|
13
|
-
return /\btable\s+has\b/i.test(step.text) &&
|
|
14
|
+
return /\btable\s+(?:has|with)\b/i.test(step.text) &&
|
|
14
15
|
/\}\}\s*rows?\b/i.test(step.text) &&
|
|
15
16
|
!!step.dataRef;
|
|
16
17
|
},
|
|
@@ -29,7 +30,8 @@ export const tablePatterns: StepPattern[] = [
|
|
|
29
30
|
priority: 16,
|
|
30
31
|
},
|
|
31
32
|
|
|
32
|
-
// "User see [Users] table has [Email] column"
|
|
33
|
+
// "User see [Users] table has [Email] column" (backward compat)
|
|
34
|
+
// Preferred: "User see [Email] column in [Users] table" (parent scoping)
|
|
33
35
|
{
|
|
34
36
|
name: 'table-column-exists',
|
|
35
37
|
matcher: (step) => {
|
|
@@ -152,11 +154,12 @@ export const tablePatterns: StepPattern[] = [
|
|
|
152
154
|
priority: 17,
|
|
153
155
|
},
|
|
154
156
|
|
|
155
|
-
// "User see [Users] table
|
|
157
|
+
// "User see [Users] table row with {{name}}" (preferred)
|
|
158
|
+
// Also accepts: "User see [Users] table has row with {{name}}" (backward compat)
|
|
156
159
|
{
|
|
157
160
|
name: 'table-row-exists',
|
|
158
161
|
matcher: (step) => {
|
|
159
|
-
return /\btable\s+has\s+row\s+with\b/i.test(step.text) && !!step.dataRef;
|
|
162
|
+
return /\btable\s+(?:has\s+)?row\s+with\b/i.test(step.text) && !!step.dataRef;
|
|
160
163
|
},
|
|
161
164
|
resolver: (step, context) => {
|
|
162
165
|
const resolved = context.selectorResolver.resolveSelector(
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Rules Updater
|
|
3
|
+
* Updates AI rules, commands, and skills from bundled templates.
|
|
4
|
+
* Used by `sungen update` command.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
|
|
10
|
+
// File mapping: [templateFile, outputPath]
|
|
11
|
+
// Shared with project-initializer.ts
|
|
12
|
+
export const AI_RULES_FILE_MAPPING: [string, string][] = [
|
|
13
|
+
// Config
|
|
14
|
+
['claude-config.md', 'CLAUDE.md'],
|
|
15
|
+
['copilot-config.md', '.github/copilot-instructions.md'],
|
|
16
|
+
|
|
17
|
+
// Commands — Claude Code
|
|
18
|
+
['claude-cmd-add-screen.md', '.claude/commands/sungen/add-screen.md'],
|
|
19
|
+
['claude-cmd-make-tc.md', '.claude/commands/sungen/make-tc.md'],
|
|
20
|
+
['claude-cmd-make-test.md', '.claude/commands/sungen/make-test.md'],
|
|
21
|
+
|
|
22
|
+
// Commands — GitHub Copilot
|
|
23
|
+
['copilot-cmd-add-screen.md', '.github/prompts/sungen-add-screen.prompt.md'],
|
|
24
|
+
['copilot-cmd-make-tc.md', '.github/prompts/sungen-make-tc.prompt.md'],
|
|
25
|
+
['copilot-cmd-make-test.md', '.github/prompts/sungen-make-test.prompt.md'],
|
|
26
|
+
|
|
27
|
+
// Skills — Claude Code
|
|
28
|
+
['claude-skill-gherkin-syntax.md', '.claude/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
29
|
+
['claude-skill-selector-keys.md', '.claude/skills/sungen-selector-keys/SKILL.md'],
|
|
30
|
+
['claude-skill-error-mapping.md', '.claude/skills/sungen-error-mapping/SKILL.md'],
|
|
31
|
+
['claude-skill-tc-generation.md', '.claude/skills/sungen-tc-generation/SKILL.md'],
|
|
32
|
+
['claude-skill-selector-fix.md', '.claude/skills/sungen-selector-fix/SKILL.md'],
|
|
33
|
+
['claude-skill-gherkin-review.md', '.claude/skills/sungen-gherkin-review/SKILL.md'],
|
|
34
|
+
|
|
35
|
+
// Skills — GitHub Copilot
|
|
36
|
+
['github-skill-sungen-gherkin-syntax.md', '.github/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
37
|
+
['github-skill-sungen-selector-keys.md', '.github/skills/sungen-selector-keys/SKILL.md'],
|
|
38
|
+
['github-skill-sungen-error-mapping.md', '.github/skills/sungen-error-mapping/SKILL.md'],
|
|
39
|
+
['github-skill-sungen-tc-generation.md', '.github/skills/sungen-tc-generation/SKILL.md'],
|
|
40
|
+
['github-skill-sungen-selector-fix.md', '.github/skills/sungen-selector-fix/SKILL.md'],
|
|
41
|
+
['github-skill-sungen-gherkin-review.md', '.github/skills/sungen-gherkin-review/SKILL.md'],
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
export class AIRulesUpdater {
|
|
45
|
+
private cwd: string;
|
|
46
|
+
private aiTemplateDir: string;
|
|
47
|
+
|
|
48
|
+
constructor(cwd: string) {
|
|
49
|
+
this.cwd = cwd;
|
|
50
|
+
this.aiTemplateDir = path.join(__dirname, 'templates', 'ai-instructions');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async update(dryRun: boolean): Promise<void> {
|
|
54
|
+
console.log('🔄 Updating AI rules, commands, and skills...\n');
|
|
55
|
+
|
|
56
|
+
const updated: string[] = [];
|
|
57
|
+
const created: string[] = [];
|
|
58
|
+
const unchanged: string[] = [];
|
|
59
|
+
const missing: string[] = [];
|
|
60
|
+
|
|
61
|
+
for (const [templateFile, outputRelPath] of AI_RULES_FILE_MAPPING) {
|
|
62
|
+
const templatePath = path.join(this.aiTemplateDir, templateFile);
|
|
63
|
+
const outputPath = path.join(this.cwd, outputRelPath);
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(templatePath)) {
|
|
66
|
+
missing.push(templateFile);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const newContent = fs.readFileSync(templatePath, 'utf-8');
|
|
71
|
+
|
|
72
|
+
if (fs.existsSync(outputPath)) {
|
|
73
|
+
const currentContent = fs.readFileSync(outputPath, 'utf-8');
|
|
74
|
+
if (currentContent === newContent) {
|
|
75
|
+
unchanged.push(outputRelPath);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!dryRun) {
|
|
80
|
+
fs.writeFileSync(outputPath, newContent, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
updated.push(outputRelPath);
|
|
83
|
+
} else {
|
|
84
|
+
if (!dryRun) {
|
|
85
|
+
const outputDir = path.dirname(outputPath);
|
|
86
|
+
if (!fs.existsSync(outputDir)) {
|
|
87
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
fs.writeFileSync(outputPath, newContent, 'utf-8');
|
|
90
|
+
}
|
|
91
|
+
created.push(outputRelPath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Print results
|
|
96
|
+
if (dryRun) {
|
|
97
|
+
console.log('📋 Dry run — no files changed\n');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (updated.length > 0) {
|
|
101
|
+
console.log(`✏️ Updated (${updated.length}):`);
|
|
102
|
+
for (const f of updated) {
|
|
103
|
+
console.log(` ${f}`);
|
|
104
|
+
}
|
|
105
|
+
console.log();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (created.length > 0) {
|
|
109
|
+
console.log(`✨ Created (${created.length}):`);
|
|
110
|
+
for (const f of created) {
|
|
111
|
+
console.log(` ${f}`);
|
|
112
|
+
}
|
|
113
|
+
console.log();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (unchanged.length > 0) {
|
|
117
|
+
console.log(`✅ Already up to date (${unchanged.length}):`);
|
|
118
|
+
for (const f of unchanged) {
|
|
119
|
+
console.log(` ${f}`);
|
|
120
|
+
}
|
|
121
|
+
console.log();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (missing.length > 0) {
|
|
125
|
+
console.log(`⚠️ Template not found (${missing.length}):`);
|
|
126
|
+
for (const f of missing) {
|
|
127
|
+
console.log(` ${f}`);
|
|
128
|
+
}
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const totalChanges = updated.length + created.length;
|
|
133
|
+
if (totalChanges === 0) {
|
|
134
|
+
console.log('All AI rules are up to date. No changes needed.');
|
|
135
|
+
} else if (dryRun) {
|
|
136
|
+
console.log(`${totalChanges} file(s) would be changed. Run without --dry-run to apply.`);
|
|
137
|
+
} else {
|
|
138
|
+
console.log(`${totalChanges} file(s) updated successfully.`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { execSync } from 'child_process';
|
|
9
|
+
import { AI_RULES_FILE_MAPPING } from './ai-rules-updater';
|
|
9
10
|
|
|
10
11
|
export class ProjectInitializer {
|
|
11
12
|
private baseCwd: string;
|
|
@@ -250,38 +251,7 @@ export class ProjectInitializer {
|
|
|
250
251
|
private createAIRules(): void {
|
|
251
252
|
const aiTemplateDir = path.join(__dirname, 'templates', 'ai-instructions');
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
const fileMapping: [string, string][] = [
|
|
255
|
-
// Config
|
|
256
|
-
['claude-config.md', 'CLAUDE.md'],
|
|
257
|
-
['copilot-config.md', '.github/copilot-instructions.md'],
|
|
258
|
-
|
|
259
|
-
// Commands — Claude Code
|
|
260
|
-
['claude-cmd-add-screen.md', '.claude/commands/sungen/add-screen.md'],
|
|
261
|
-
['claude-cmd-make-tc.md', '.claude/commands/sungen/make-tc.md'],
|
|
262
|
-
['claude-cmd-make-test.md', '.claude/commands/sungen/make-test.md'],
|
|
263
|
-
|
|
264
|
-
// Commands — GitHub Copilot
|
|
265
|
-
['copilot-cmd-add-screen.md', '.github/prompts/sungen-add-screen.prompt.md'],
|
|
266
|
-
['copilot-cmd-make-tc.md', '.github/prompts/sungen-make-tc.prompt.md'],
|
|
267
|
-
['copilot-cmd-make-test.md', '.github/prompts/sungen-make-test.prompt.md'],
|
|
268
|
-
|
|
269
|
-
// Skills — Claude Code
|
|
270
|
-
['claude-skill-gherkin-syntax.md', '.claude/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
271
|
-
['claude-skill-selector-keys.md', '.claude/skills/sungen-selector-keys/SKILL.md'],
|
|
272
|
-
['claude-skill-error-mapping.md', '.claude/skills/sungen-error-mapping/SKILL.md'],
|
|
273
|
-
['claude-skill-tc-generation.md', '.claude/skills/sungen-tc-generation/SKILL.md'],
|
|
274
|
-
['claude-skill-selector-fix.md', '.claude/skills/sungen-selector-fix/SKILL.md'],
|
|
275
|
-
|
|
276
|
-
// Skills — GitHub Copilot (separate copies with Copilot-friendly descriptions)
|
|
277
|
-
['github-skill-sungen-gherkin-syntax.md', '.github/skills/sungen-gherkin-syntax/SKILL.md'],
|
|
278
|
-
['github-skill-sungen-selector-keys.md', '.github/skills/sungen-selector-keys/SKILL.md'],
|
|
279
|
-
['github-skill-sungen-error-mapping.md', '.github/skills/sungen-error-mapping/SKILL.md'],
|
|
280
|
-
['github-skill-sungen-tc-generation.md', '.github/skills/sungen-tc-generation/SKILL.md'],
|
|
281
|
-
['github-skill-sungen-selector-fix.md', '.github/skills/sungen-selector-fix/SKILL.md'],
|
|
282
|
-
];
|
|
283
|
-
|
|
284
|
-
for (const [templateFile, outputRelPath] of fileMapping) {
|
|
254
|
+
for (const [templateFile, outputRelPath] of AI_RULES_FILE_MAPPING) {
|
|
285
255
|
const outputPath = path.join(this.cwd, outputRelPath);
|
|
286
256
|
|
|
287
257
|
if (fs.existsSync(outputPath)) {
|
|
@@ -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)}
|
|
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.
|
|
122
|
-
console.log(`
|
|
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.
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
###
|
|
47
|
+
### 4. Confirm
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
-
|
|
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,17 @@ 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.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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` exists → read 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. **Self-review** — re-read the `.feature` file and apply the full **`sungen-gherkin-review` skill**: assertion quality rules (4 rules), action-result coherence (5 rules), and the 9-point quality checklist. **Auto-fix any issues found**, then re-read to verify.
|
|
31
|
+
8. Show summary → next: `/sungen:make-test <screen>`
|
|
24
32
|
|
|
25
33
|
**No selectors.yaml** — selectors are generated during `/sungen:make-test`.
|
|
@@ -16,16 +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
|
|
20
|
-
3.
|
|
21
|
-
4. **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
- Repeat until no failures remain or max attempts reached
|
|
29
|
-
6. **Final confirmation** — run ALL tests once to ensure no regressions.
|
|
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.
|
|
30
28
|
7. After 5 fix attempts still failing → ask user about direct `.spec.ts` fix.
|
|
31
29
|
8. Show: pass/fail, attempt count, files changed.
|