@sun-asterisk/sungen 2.4.5 → 2.4.6

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 (129) hide show
  1. package/dist/cli/commands/delivery.d.ts +7 -0
  2. package/dist/cli/commands/delivery.d.ts.map +1 -0
  3. package/dist/cli/commands/delivery.js +348 -0
  4. package/dist/cli/commands/delivery.js.map +1 -0
  5. package/dist/cli/commands/update.d.ts.map +1 -1
  6. package/dist/cli/commands/update.js +64 -1
  7. package/dist/cli/commands/update.js.map +1 -1
  8. package/dist/cli/index.js +4 -2
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/exporters/csv-exporter.d.ts +32 -0
  11. package/dist/exporters/csv-exporter.d.ts.map +1 -0
  12. package/dist/exporters/csv-exporter.js +311 -0
  13. package/dist/exporters/csv-exporter.js.map +1 -0
  14. package/dist/exporters/feature-parser.d.ts +48 -0
  15. package/dist/exporters/feature-parser.d.ts.map +1 -0
  16. package/dist/exporters/feature-parser.js +178 -0
  17. package/dist/exporters/feature-parser.js.map +1 -0
  18. package/dist/exporters/package-info.d.ts +9 -0
  19. package/dist/exporters/package-info.d.ts.map +1 -0
  20. package/dist/exporters/package-info.js +73 -0
  21. package/dist/exporters/package-info.js.map +1 -0
  22. package/dist/exporters/playwright-report-parser.d.ts +21 -0
  23. package/dist/exporters/playwright-report-parser.d.ts.map +1 -0
  24. package/dist/exporters/playwright-report-parser.js +184 -0
  25. package/dist/exporters/playwright-report-parser.js.map +1 -0
  26. package/dist/exporters/scenario-merger.d.ts +21 -0
  27. package/dist/exporters/scenario-merger.d.ts.map +1 -0
  28. package/dist/exporters/scenario-merger.js +51 -0
  29. package/dist/exporters/scenario-merger.js.map +1 -0
  30. package/dist/exporters/spec-parser.d.ts +20 -0
  31. package/dist/exporters/spec-parser.d.ts.map +1 -0
  32. package/dist/exporters/spec-parser.js +259 -0
  33. package/dist/exporters/spec-parser.js.map +1 -0
  34. package/dist/exporters/step-formatter.d.ts +32 -0
  35. package/dist/exporters/step-formatter.d.ts.map +1 -0
  36. package/dist/exporters/step-formatter.js +76 -0
  37. package/dist/exporters/step-formatter.js.map +1 -0
  38. package/dist/exporters/test-data-resolver.d.ts +20 -0
  39. package/dist/exporters/test-data-resolver.d.ts.map +1 -0
  40. package/dist/exporters/test-data-resolver.js +96 -0
  41. package/dist/exporters/test-data-resolver.js.map +1 -0
  42. package/dist/exporters/types.d.ts +104 -0
  43. package/dist/exporters/types.d.ts.map +1 -0
  44. package/dist/exporters/types.js +6 -0
  45. package/dist/exporters/types.js.map +1 -0
  46. package/dist/exporters/xlsx-exporter.d.ts +19 -0
  47. package/dist/exporters/xlsx-exporter.d.ts.map +1 -0
  48. package/dist/exporters/xlsx-exporter.js +309 -0
  49. package/dist/exporters/xlsx-exporter.js.map +1 -0
  50. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  51. package/dist/generators/test-generator/utils/selector-resolver.js +26 -0
  52. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  53. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  54. package/dist/orchestrator/ai-rules-updater.js +12 -0
  55. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  56. package/dist/orchestrator/project-initializer.d.ts +12 -1
  57. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  58. package/dist/orchestrator/project-initializer.js +84 -64
  59. package/dist/orchestrator/project-initializer.js.map +1 -1
  60. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  61. package/dist/orchestrator/screen-manager.js +2 -0
  62. package/dist/orchestrator/screen-manager.js.map +1 -1
  63. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +15 -17
  64. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +7 -5
  65. package/dist/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +71 -0
  66. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +27 -0
  67. package/dist/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  68. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +142 -0
  69. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +100 -0
  70. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +73 -0
  71. package/dist/orchestrator/templates/ai-instructions/claude-skill-delivery.md +103 -0
  72. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +2 -0
  73. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +22 -0
  74. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -15
  75. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +6 -4
  76. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +71 -0
  77. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +38 -14
  78. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  79. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +142 -0
  80. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +100 -0
  81. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +73 -0
  82. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +103 -0
  83. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +2 -0
  84. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +22 -0
  85. package/dist/orchestrator/templates/playwright.config.d.ts.map +1 -1
  86. package/dist/orchestrator/templates/playwright.config.js +6 -1
  87. package/dist/orchestrator/templates/playwright.config.js.map +1 -1
  88. package/dist/orchestrator/templates/playwright.config.ts +6 -1
  89. package/package.json +2 -1
  90. package/src/cli/commands/delivery.ts +348 -0
  91. package/src/cli/commands/update.ts +84 -2
  92. package/src/cli/index.ts +4 -2
  93. package/src/exporters/csv-exporter.ts +304 -0
  94. package/src/exporters/feature-parser.ts +168 -0
  95. package/src/exporters/package-info.ts +35 -0
  96. package/src/exporters/playwright-report-parser.ts +168 -0
  97. package/src/exporters/scenario-merger.ts +63 -0
  98. package/src/exporters/spec-parser.ts +247 -0
  99. package/src/exporters/step-formatter.ts +80 -0
  100. package/src/exporters/test-data-resolver.ts +59 -0
  101. package/src/exporters/types.ts +112 -0
  102. package/src/exporters/xlsx-exporter.ts +301 -0
  103. package/src/generators/test-generator/utils/selector-resolver.ts +26 -0
  104. package/src/orchestrator/ai-rules-updater.ts +12 -0
  105. package/src/orchestrator/project-initializer.ts +103 -70
  106. package/src/orchestrator/screen-manager.ts +2 -0
  107. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +15 -17
  108. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +7 -5
  109. package/src/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +71 -0
  110. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +27 -0
  111. package/src/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  112. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +142 -0
  113. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +100 -0
  114. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +73 -0
  115. package/src/orchestrator/templates/ai-instructions/claude-skill-delivery.md +103 -0
  116. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +2 -0
  117. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +22 -0
  118. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +13 -15
  119. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +6 -4
  120. package/src/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +71 -0
  121. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +38 -14
  122. package/src/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  123. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +142 -0
  124. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +100 -0
  125. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +73 -0
  126. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +103 -0
  127. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +2 -0
  128. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +22 -0
  129. package/src/orchestrator/templates/playwright.config.ts +6 -1
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Parse Playwright results.json (JSON reporter output) to map test titles → execution status.
3
+ */
4
+ import { PlaywrightResult } from './types';
5
+ /**
6
+ * Load and parse results.json. Returns null if file missing or invalid.
7
+ */
8
+ export declare function loadPlaywrightReport(reportPath: string): Map<string, PlaywrightResult> | null;
9
+ /**
10
+ * CSV "Test Result" column mapping.
11
+ */
12
+ export declare function statusToTestResult(status: PlaywrightResult['status']): string;
13
+ /**
14
+ * Format startTime (ISO string) → "dd/mm/yyyy".
15
+ */
16
+ export declare function formatExecutedDate(startTime: string | undefined): string;
17
+ /**
18
+ * Format error message for Note column. Truncate long stacks, include trace path.
19
+ */
20
+ export declare function formatNote(result: PlaywrightResult | undefined): string;
21
+ //# sourceMappingURL=playwright-report-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-report-parser.d.ts","sourceRoot":"","sources":["../../src/exporters/playwright-report-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAkD3C;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,IAAI,CAqC7F;AA4BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAAG,MAAM,CAc7E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,MAAM,CASvE"}
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ /**
3
+ * Parse Playwright results.json (JSON reporter output) to map test titles → execution status.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.loadPlaywrightReport = loadPlaywrightReport;
40
+ exports.statusToTestResult = statusToTestResult;
41
+ exports.formatExecutedDate = formatExecutedDate;
42
+ exports.formatNote = formatNote;
43
+ const fs = __importStar(require("fs"));
44
+ /**
45
+ * Recursively walk suites and collect (full-title → spec) pairs.
46
+ * Title stack is joined with " > " to match our SpecTest.testTitle format.
47
+ */
48
+ function walkSuites(suites, titleStack) {
49
+ const map = new Map();
50
+ if (!suites)
51
+ return map;
52
+ for (const suite of suites) {
53
+ const nextStack = suite.title ? [...titleStack, suite.title] : titleStack;
54
+ for (const spec of suite.specs || []) {
55
+ if (spec.title) {
56
+ const fullTitle = [...nextStack, spec.title].join(' > ');
57
+ map.set(fullTitle, spec);
58
+ }
59
+ }
60
+ const childMap = walkSuites(suite.suites, nextStack);
61
+ for (const [k, v] of childMap.entries())
62
+ map.set(k, v);
63
+ }
64
+ return map;
65
+ }
66
+ /**
67
+ * Load and parse results.json. Returns null if file missing or invalid.
68
+ */
69
+ function loadPlaywrightReport(reportPath) {
70
+ if (!fs.existsSync(reportPath))
71
+ return null;
72
+ let raw;
73
+ try {
74
+ const content = fs.readFileSync(reportPath, 'utf-8');
75
+ raw = JSON.parse(content);
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ // The top-level "suites" array uses the spec file path as suite.title.
81
+ // Tests are nested deeper under describe() blocks.
82
+ // We walk all suites and map "describeTitle > nestedTitle > specTitle" → spec.
83
+ const specMap = walkSuites(raw.suites, []);
84
+ const result = new Map();
85
+ for (const [fullTitle, spec] of specMap.entries()) {
86
+ const test = spec.tests?.[0];
87
+ const res = test?.results?.[0];
88
+ const status = normalizeStatus(res?.status);
89
+ const errorMsg = res?.error?.message || '';
90
+ const trace = res?.attachments?.find((a) => a.name === 'trace' || a.contentType === 'application/zip')?.path;
91
+ // Strip the leading file-path suite title if present.
92
+ // The top-level suite title is usually a file path like "specs/generated/kudos/kudos.spec.ts".
93
+ // The test title we match against is "<Feature> > <auth> > <Scenario>".
94
+ const stripped = stripLeadingFilePathSuite(fullTitle);
95
+ result.set(stripped, {
96
+ testTitle: stripped,
97
+ status,
98
+ startTime: res?.startTime,
99
+ error: errorMsg,
100
+ tracePath: trace,
101
+ });
102
+ }
103
+ return result;
104
+ }
105
+ /**
106
+ * Normalize playwright status strings to our enum.
107
+ */
108
+ function normalizeStatus(s) {
109
+ if (!s)
110
+ return 'unknown';
111
+ if (s === 'passed')
112
+ return 'passed';
113
+ if (s === 'failed')
114
+ return 'failed';
115
+ if (s === 'timedOut')
116
+ return 'timedOut';
117
+ if (s === 'skipped')
118
+ return 'skipped';
119
+ if (s === 'interrupted')
120
+ return 'interrupted';
121
+ return 'unknown';
122
+ }
123
+ /**
124
+ * If the full title starts with a file-path-looking suite title like
125
+ * "specs/generated/kudos/kudos.spec.ts > Feature Name > ...",
126
+ * strip that leading segment so matching works against "Feature Name > ...".
127
+ */
128
+ function stripLeadingFilePathSuite(fullTitle) {
129
+ const parts = fullTitle.split(' > ');
130
+ if (parts.length > 1 && /\.spec\.ts$/i.test(parts[0])) {
131
+ return parts.slice(1).join(' > ');
132
+ }
133
+ return fullTitle;
134
+ }
135
+ /**
136
+ * CSV "Test Result" column mapping.
137
+ */
138
+ function statusToTestResult(status) {
139
+ switch (status) {
140
+ case 'passed':
141
+ return 'Passed';
142
+ case 'failed':
143
+ case 'timedOut':
144
+ return 'Failed';
145
+ case 'skipped':
146
+ return 'N/A';
147
+ case 'interrupted':
148
+ return 'Pending';
149
+ default:
150
+ return 'Pending';
151
+ }
152
+ }
153
+ /**
154
+ * Format startTime (ISO string) → "dd/mm/yyyy".
155
+ */
156
+ function formatExecutedDate(startTime) {
157
+ if (!startTime)
158
+ return '';
159
+ const d = new Date(startTime);
160
+ if (isNaN(d.getTime()))
161
+ return '';
162
+ const dd = String(d.getDate()).padStart(2, '0');
163
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
164
+ const yyyy = d.getFullYear();
165
+ return `${dd}/${mm}/${yyyy}`;
166
+ }
167
+ /**
168
+ * Format error message for Note column. Truncate long stacks, include trace path.
169
+ */
170
+ function formatNote(result) {
171
+ if (!result)
172
+ return '';
173
+ if (result.status !== 'failed' && result.status !== 'timedOut')
174
+ return '';
175
+ const firstLine = (result.error || '').split('\n')[0].trim();
176
+ const truncated = firstLine.length > 200 ? firstLine.substring(0, 197) + '…' : firstLine;
177
+ const parts = [];
178
+ if (truncated)
179
+ parts.push(`Error: ${truncated}`);
180
+ if (result.tracePath)
181
+ parts.push(`Trace: ${result.tracePath}`);
182
+ return parts.join('. ');
183
+ }
184
+ //# sourceMappingURL=playwright-report-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-report-parser.js","sourceRoot":"","sources":["../../src/exporters/playwright-report-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Cross-validate .feature scenarios against compiled .spec.ts tests.
3
+ * Produces a merged view for CSV row assembly.
4
+ *
5
+ * Priority of truth:
6
+ * - .spec.ts (resolved Playwright calls) is the source of truth for Steps/Expected
7
+ * - .feature (tags, VP ID, referenced vars) is source for metadata
8
+ * - Scenarios in .feature but NOT in .spec.ts → marked "Not compiled"
9
+ */
10
+ import { FeatureMetadata, ScenarioMetadata, SpecFileData, SpecTest } from './types';
11
+ export interface MergedScenario {
12
+ /** Scenario metadata from .feature */
13
+ feature: ScenarioMetadata;
14
+ /** Matched compiled test from .spec.ts, or null if not compiled. */
15
+ spec: SpecTest | null;
16
+ }
17
+ /**
18
+ * Merge features and spec data, excluding base @steps and scaffold scenarios.
19
+ */
20
+ export declare function mergeFeatureAndSpec(feature: FeatureMetadata, spec: SpecFileData): MergedScenario[];
21
+ //# sourceMappingURL=scenario-merger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-merger.d.ts","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGpF,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,OAAO,EAAE,gBAAgB,CAAC;IAE1B,oEAAoE;IACpE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,YAAY,GACjB,cAAc,EAAE,CAelB"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-validate .feature scenarios against compiled .spec.ts tests.
4
+ * Produces a merged view for CSV row assembly.
5
+ *
6
+ * Priority of truth:
7
+ * - .spec.ts (resolved Playwright calls) is the source of truth for Steps/Expected
8
+ * - .feature (tags, VP ID, referenced vars) is source for metadata
9
+ * - Scenarios in .feature but NOT in .spec.ts → marked "Not compiled"
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.mergeFeatureAndSpec = mergeFeatureAndSpec;
13
+ const feature_parser_1 = require("./feature-parser");
14
+ /**
15
+ * Merge features and spec data, excluding base @steps and scaffold scenarios.
16
+ */
17
+ function mergeFeatureAndSpec(feature, spec) {
18
+ const result = [];
19
+ for (const scenario of feature.scenarios) {
20
+ if ((0, feature_parser_1.isStepsBaseScenario)(scenario))
21
+ continue; // skip @steps base scenarios
22
+ if ((0, feature_parser_1.isSampleScaffoldScenario)(scenario))
23
+ continue; // skip default sample
24
+ const specTest = findMatchingSpecTest(scenario, spec.tests);
25
+ result.push({
26
+ feature: scenario,
27
+ spec: specTest,
28
+ });
29
+ }
30
+ return result;
31
+ }
32
+ /**
33
+ * Find the spec test that corresponds to a given feature scenario.
34
+ * Match by scenario title (exact match on the scenario name).
35
+ */
36
+ function findMatchingSpecTest(scenario, tests) {
37
+ // Exact title match
38
+ const exact = tests.find((t) => t.scenarioName === scenario.name);
39
+ if (exact)
40
+ return exact;
41
+ // Fallback: match by VP-ID prefix (ignore trailing text differences)
42
+ const vpMatch = scenario.name.match(/^(VP-[A-Z]+-\d+[a-zA-Z]?)/);
43
+ if (vpMatch) {
44
+ const vpId = vpMatch[1];
45
+ const byVp = tests.find((t) => t.vpId === vpId);
46
+ if (byVp)
47
+ return byVp;
48
+ }
49
+ return null;
50
+ }
51
+ //# sourceMappingURL=scenario-merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-merger.js","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAgBH,kDAkBC;AA/BD,qDAAiF;AAUjF;;GAEG;AACH,SAAgB,mBAAmB,CACjC,OAAwB,EACxB,IAAkB;IAElB,MAAM,MAAM,GAAqB,EAAE,CAAC;IAEpC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACzC,IAAI,IAAA,oCAAmB,EAAC,QAAQ,CAAC;YAAE,SAAS,CAAO,6BAA6B;QAChF,IAAI,IAAA,yCAAwB,EAAC,QAAQ,CAAC;YAAE,SAAS,CAAE,sBAAsB;QAEzE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ;YACjB,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,QAA0B,EAAE,KAAiB;IACzE,oBAAoB;IACpB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClE,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,qEAAqE;IACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACjE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAChD,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Parse compiled .spec.ts files to extract resolved test structure.
3
+ * Uses regex parsing (not TS AST) since files are auto-generated with stable format.
4
+ */
5
+ import { SpecFileData } from './types';
6
+ /**
7
+ * Parse a compiled .spec.ts file.
8
+ *
9
+ * Structure:
10
+ * test.describe('<Feature Name>', () => {
11
+ * test.describe('<auth role>', () => { // optional nesting
12
+ * test.use({ storageState: '...' });
13
+ * test('<title>', async ({ page }) => { ... });
14
+ * ...
15
+ * });
16
+ * test('<title>', async ({ page }) => { ... }); // no-auth cases at top level
17
+ * });
18
+ */
19
+ export declare function parseSpecFile(specFilePath: string): SpecFileData;
20
+ //# sourceMappingURL=spec-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-parser.d.ts","sourceRoot":"","sources":["../../src/exporters/spec-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAY,YAAY,EAAE,MAAM,SAAS,CAAC;AAoIjD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CA+ChE"}
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ /**
3
+ * Parse compiled .spec.ts files to extract resolved test structure.
4
+ * Uses regex parsing (not TS AST) since files are auto-generated with stable format.
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.parseSpecFile = parseSpecFile;
41
+ const fs = __importStar(require("fs"));
42
+ /**
43
+ * Extract the inner body of a test('title', async (...) => { BODY }) block.
44
+ * Returns null if no match.
45
+ */
46
+ function extractTestBlock(content, startIdx) {
47
+ // Match test('title', async ({ page }) => {
48
+ const testRegex = /test\s*\(\s*['"]([^'"]+)['"]\s*,\s*async\s*\([^)]*\)\s*=>\s*\{/g;
49
+ testRegex.lastIndex = startIdx;
50
+ const match = testRegex.exec(content);
51
+ if (!match)
52
+ return null;
53
+ const title = match[1];
54
+ const bodyStart = match.index + match[0].length;
55
+ // Find matching closing brace (accounting for nested braces)
56
+ let depth = 1;
57
+ let i = bodyStart;
58
+ while (i < content.length && depth > 0) {
59
+ const ch = content[i];
60
+ if (ch === '{')
61
+ depth++;
62
+ else if (ch === '}')
63
+ depth--;
64
+ if (depth === 0)
65
+ break;
66
+ i++;
67
+ }
68
+ if (depth !== 0)
69
+ return null;
70
+ const body = content.substring(bodyStart, i);
71
+ // The closing `)` of the arrow function call comes after the `}`, e.g., `});` — skip it
72
+ const endIdx = content.indexOf(';', i) + 1;
73
+ return { title, body, endIdx };
74
+ }
75
+ /**
76
+ * Find describe('name', ...) blocks and return their names + body ranges.
77
+ */
78
+ function extractDescribeBlocks(content) {
79
+ const result = [];
80
+ const regex = /test\.describe\s*\(\s*['"]([^'"]+)['"]\s*,\s*\(\s*\)\s*=>\s*\{/g;
81
+ let match;
82
+ while ((match = regex.exec(content)) !== null) {
83
+ const name = match[1];
84
+ const bodyStart = match.index + match[0].length;
85
+ let depth = 1;
86
+ let i = bodyStart;
87
+ while (i < content.length && depth > 0) {
88
+ const ch = content[i];
89
+ if (ch === '{')
90
+ depth++;
91
+ else if (ch === '}')
92
+ depth--;
93
+ if (depth === 0)
94
+ break;
95
+ i++;
96
+ }
97
+ result.push({ name, bodyStart, bodyEnd: i });
98
+ }
99
+ return result;
100
+ }
101
+ /**
102
+ * Tokenize test body into code blocks.
103
+ * Each block = one or more `// <comment>` lines, followed by `await ...` lines until the next comment.
104
+ */
105
+ function tokenizeBody(body) {
106
+ const lines = body.split('\n').map((l) => l.trim()).filter((l) => l.length > 0);
107
+ const blocks = [];
108
+ let currentComment = '';
109
+ let currentCode = [];
110
+ const flush = () => {
111
+ if (currentComment || currentCode.length > 0) {
112
+ blocks.push({ comment: currentComment, code: [...currentCode] });
113
+ }
114
+ currentComment = '';
115
+ currentCode = [];
116
+ };
117
+ for (const line of lines) {
118
+ if (line.startsWith('//')) {
119
+ // A new comment boundary — flush the previous block first if it has code
120
+ if (currentCode.length > 0)
121
+ flush();
122
+ currentComment = line.replace(/^\/\/\s*/, '').trim();
123
+ }
124
+ else if (line.startsWith('await ') || line.startsWith('await\t')) {
125
+ currentCode.push(line);
126
+ }
127
+ else if (line.endsWith(';') || line.endsWith('{') || line.endsWith('}')) {
128
+ // Continuation of an await (multi-line code) OR block-structure like `{ ... }`
129
+ if (currentCode.length > 0) {
130
+ currentCode[currentCode.length - 1] += ' ' + line;
131
+ }
132
+ }
133
+ }
134
+ flush();
135
+ return blocks;
136
+ }
137
+ /**
138
+ * Classify a CodeBlock into precondition / step / expectation.
139
+ *
140
+ * Rules:
141
+ * - Starts with page.goto or is from @steps setup → precondition
142
+ * - Contains `expect(` → expectation
143
+ * - Otherwise → step (action)
144
+ *
145
+ * Additional heuristic: if the comment matches "Open <screen> page" or similar
146
+ * setup verbs, treat as precondition even if not first.
147
+ */
148
+ function classifyBlock(block) {
149
+ const codeJoined = block.code.join(' ');
150
+ if (codeJoined.includes('expect('))
151
+ return 'expectation';
152
+ if (codeJoined.includes('page.goto('))
153
+ return 'precondition';
154
+ return 'step';
155
+ }
156
+ /**
157
+ * Try to extract VP ID (e.g., VP-UI-001) from the start of a scenario title.
158
+ */
159
+ function extractVpId(title) {
160
+ const match = title.match(/^(VP-[A-Z]+-\d+[a-zA-Z]?)\b/);
161
+ return match ? match[1] : undefined;
162
+ }
163
+ /**
164
+ * Parse a compiled .spec.ts file.
165
+ *
166
+ * Structure:
167
+ * test.describe('<Feature Name>', () => {
168
+ * test.describe('<auth role>', () => { // optional nesting
169
+ * test.use({ storageState: '...' });
170
+ * test('<title>', async ({ page }) => { ... });
171
+ * ...
172
+ * });
173
+ * test('<title>', async ({ page }) => { ... }); // no-auth cases at top level
174
+ * });
175
+ */
176
+ function parseSpecFile(specFilePath) {
177
+ if (!fs.existsSync(specFilePath)) {
178
+ return { tests: [] };
179
+ }
180
+ const content = fs.readFileSync(specFilePath, 'utf-8');
181
+ const tests = [];
182
+ const describes = extractDescribeBlocks(content);
183
+ if (describes.length === 0)
184
+ return { tests: [] };
185
+ // First describe is the feature-level one
186
+ const featureDescribe = describes[0];
187
+ const featureName = featureDescribe.name;
188
+ // Nested auth describes live inside the feature describe range
189
+ const nestedAuthDescribes = describes.filter((d) => d !== featureDescribe && d.bodyStart > featureDescribe.bodyStart && d.bodyEnd < featureDescribe.bodyEnd);
190
+ // Collect tests inside each nested auth describe
191
+ const processedRanges = [];
192
+ for (const authDesc of nestedAuthDescribes) {
193
+ const innerBody = content.substring(authDesc.bodyStart, authDesc.bodyEnd);
194
+ const innerTests = collectTestsFromBody(innerBody, featureName, authDesc.name);
195
+ tests.push(...innerTests);
196
+ processedRanges.push([authDesc.bodyStart, authDesc.bodyEnd]);
197
+ }
198
+ // Collect tests at the feature level that are NOT inside any nested auth describe
199
+ // i.e., top-level tests (no auth / @no-auth scenarios)
200
+ let cursor = featureDescribe.bodyStart;
201
+ const featureBodyEnd = featureDescribe.bodyEnd;
202
+ while (cursor < featureBodyEnd) {
203
+ // Skip any nested describe range
204
+ const nextSkip = processedRanges.find(([s, e]) => s > cursor && s < featureBodyEnd && e > cursor);
205
+ const searchEnd = nextSkip ? nextSkip[0] : featureBodyEnd;
206
+ const slice = content.substring(cursor, searchEnd);
207
+ const sliceTests = collectTestsFromBody(slice, featureName, undefined);
208
+ tests.push(...sliceTests);
209
+ cursor = nextSkip ? nextSkip[1] : featureBodyEnd;
210
+ }
211
+ return { tests };
212
+ }
213
+ function collectTestsFromBody(body, describeName, authRole) {
214
+ const tests = [];
215
+ let cursor = 0;
216
+ while (cursor < body.length) {
217
+ const block = extractTestBlock(body, cursor);
218
+ if (!block)
219
+ break;
220
+ const codeBlocks = tokenizeBody(block.body);
221
+ const precondition = [];
222
+ const steps = [];
223
+ const expectations = [];
224
+ for (const cb of codeBlocks) {
225
+ const category = classifyBlock(cb);
226
+ const line = cb.comment || cb.code.join(' ');
227
+ if (category === 'precondition')
228
+ precondition.push(line);
229
+ else if (category === 'step')
230
+ steps.push(line);
231
+ else
232
+ expectations.push(line);
233
+ }
234
+ tests.push({
235
+ describeName,
236
+ authRole,
237
+ testTitle: buildFullTestTitle(describeName, authRole, block.title),
238
+ scenarioName: block.title,
239
+ vpId: extractVpId(block.title),
240
+ precondition,
241
+ steps,
242
+ expectations,
243
+ });
244
+ cursor = block.endIdx;
245
+ }
246
+ return tests;
247
+ }
248
+ /**
249
+ * Build full test title matching Playwright report format:
250
+ * "<Feature Name> > <auth role> > <scenario title>"
251
+ * Playwright separator is " > " in CLI output, but internally it uses title arrays.
252
+ */
253
+ function buildFullTestTitle(featureName, authRole, scenarioTitle) {
254
+ if (authRole) {
255
+ return `${featureName} > ${authRole} > ${scenarioTitle}`;
256
+ }
257
+ return `${featureName} > ${scenarioTitle}`;
258
+ }
259
+ //# sourceMappingURL=spec-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-parser.js","sourceRoot":"","sources":["../../src/exporters/spec-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Convert raw Gherkin step text OR generated .spec.ts comment lines into
3
+ * concise, numbered natural language for the CSV Steps/Expected columns.
4
+ *
5
+ * Deterministic — no AI calls.
6
+ */
7
+ /**
8
+ * Format a list of raw step lines for the Steps / Expected Results columns.
9
+ *
10
+ * - 0 lines → empty string
11
+ * - 1 line → the line verbatim (no "1. " prefix — avoids Google Sheets clutter)
12
+ * - ≥ 2 → each line on its own row, "1. ", "2. ", … prefixes, newline-joined
13
+ * so spreadsheet cells auto-wrap one step per visual line.
14
+ */
15
+ export declare function formatNumberedSteps(lines: string[]): string;
16
+ /**
17
+ * Clean a raw step line (either Gherkin text or .spec.ts comment).
18
+ *
19
+ * Handles patterns like:
20
+ * "User click [login] button" → "Click 'login' button"
21
+ * "User fill [Email] field with {{email}}" → "Fill 'Email' field with {{email}}"
22
+ * "Click Signature 2025 Creator" → "Click 'Signature 2025 Creator'"
23
+ * "Assert title error has text err_xxx" → "Title error has text err_xxx"
24
+ * "Open awards page" → "Open awards page"
25
+ */
26
+ export declare function cleanStepLine(raw: string): string;
27
+ /**
28
+ * Natural language for Given → Pre-condition.
29
+ * Combines auth info + Given steps into a single sentence.
30
+ */
31
+ export declare function formatPrecondition(authRole: string | null, givenLines: string[]): string;
32
+ //# sourceMappingURL=step-formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-formatter.d.ts","sourceRoot":"","sources":["../../src/exporters/step-formatter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAK3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBjD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,CAkBR"}