@sun-asterisk/sungen 2.4.3 → 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 (138) hide show
  1. package/dist/cli/commands/add.d.ts.map +1 -1
  2. package/dist/cli/commands/add.js +8 -2
  3. package/dist/cli/commands/add.js.map +1 -1
  4. package/dist/cli/commands/delivery.d.ts +7 -0
  5. package/dist/cli/commands/delivery.d.ts.map +1 -0
  6. package/dist/cli/commands/delivery.js +348 -0
  7. package/dist/cli/commands/delivery.js.map +1 -0
  8. package/dist/cli/commands/update.d.ts.map +1 -1
  9. package/dist/cli/commands/update.js +64 -1
  10. package/dist/cli/commands/update.js.map +1 -1
  11. package/dist/cli/index.js +4 -2
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/exporters/csv-exporter.d.ts +32 -0
  14. package/dist/exporters/csv-exporter.d.ts.map +1 -0
  15. package/dist/exporters/csv-exporter.js +311 -0
  16. package/dist/exporters/csv-exporter.js.map +1 -0
  17. package/dist/exporters/feature-parser.d.ts +48 -0
  18. package/dist/exporters/feature-parser.d.ts.map +1 -0
  19. package/dist/exporters/feature-parser.js +178 -0
  20. package/dist/exporters/feature-parser.js.map +1 -0
  21. package/dist/exporters/package-info.d.ts +9 -0
  22. package/dist/exporters/package-info.d.ts.map +1 -0
  23. package/dist/exporters/package-info.js +73 -0
  24. package/dist/exporters/package-info.js.map +1 -0
  25. package/dist/exporters/playwright-report-parser.d.ts +21 -0
  26. package/dist/exporters/playwright-report-parser.d.ts.map +1 -0
  27. package/dist/exporters/playwright-report-parser.js +184 -0
  28. package/dist/exporters/playwright-report-parser.js.map +1 -0
  29. package/dist/exporters/scenario-merger.d.ts +21 -0
  30. package/dist/exporters/scenario-merger.d.ts.map +1 -0
  31. package/dist/exporters/scenario-merger.js +51 -0
  32. package/dist/exporters/scenario-merger.js.map +1 -0
  33. package/dist/exporters/spec-parser.d.ts +20 -0
  34. package/dist/exporters/spec-parser.d.ts.map +1 -0
  35. package/dist/exporters/spec-parser.js +259 -0
  36. package/dist/exporters/spec-parser.js.map +1 -0
  37. package/dist/exporters/step-formatter.d.ts +32 -0
  38. package/dist/exporters/step-formatter.d.ts.map +1 -0
  39. package/dist/exporters/step-formatter.js +76 -0
  40. package/dist/exporters/step-formatter.js.map +1 -0
  41. package/dist/exporters/test-data-resolver.d.ts +20 -0
  42. package/dist/exporters/test-data-resolver.d.ts.map +1 -0
  43. package/dist/exporters/test-data-resolver.js +96 -0
  44. package/dist/exporters/test-data-resolver.js.map +1 -0
  45. package/dist/exporters/types.d.ts +104 -0
  46. package/dist/exporters/types.d.ts.map +1 -0
  47. package/dist/exporters/types.js +6 -0
  48. package/dist/exporters/types.js.map +1 -0
  49. package/dist/exporters/xlsx-exporter.d.ts +19 -0
  50. package/dist/exporters/xlsx-exporter.d.ts.map +1 -0
  51. package/dist/exporters/xlsx-exporter.js +309 -0
  52. package/dist/exporters/xlsx-exporter.js.map +1 -0
  53. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  54. package/dist/generators/test-generator/utils/selector-resolver.js +26 -0
  55. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  56. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  57. package/dist/orchestrator/ai-rules-updater.js +12 -0
  58. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  59. package/dist/orchestrator/project-initializer.d.ts +12 -1
  60. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  61. package/dist/orchestrator/project-initializer.js +84 -64
  62. package/dist/orchestrator/project-initializer.js.map +1 -1
  63. package/dist/orchestrator/screen-manager.d.ts +1 -0
  64. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  65. package/dist/orchestrator/screen-manager.js +4 -2
  66. package/dist/orchestrator/screen-manager.js.map +1 -1
  67. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
  68. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +7 -5
  69. package/dist/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +71 -0
  70. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +38 -10
  71. package/dist/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  72. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +142 -0
  73. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +100 -0
  74. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +73 -0
  75. package/dist/orchestrator/templates/ai-instructions/claude-skill-delivery.md +103 -0
  76. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +2 -0
  77. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +87 -4
  78. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +22 -0
  79. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +18 -9
  80. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +6 -4
  81. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +71 -0
  82. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +45 -20
  83. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  84. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +142 -0
  85. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +100 -0
  86. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +73 -0
  87. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +103 -0
  88. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +2 -0
  89. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +87 -4
  90. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +22 -0
  91. package/dist/orchestrator/templates/playwright.config.d.ts.map +1 -1
  92. package/dist/orchestrator/templates/playwright.config.js +6 -1
  93. package/dist/orchestrator/templates/playwright.config.js.map +1 -1
  94. package/dist/orchestrator/templates/playwright.config.ts +6 -1
  95. package/package.json +2 -1
  96. package/src/cli/commands/add.ts +9 -2
  97. package/src/cli/commands/delivery.ts +348 -0
  98. package/src/cli/commands/update.ts +84 -2
  99. package/src/cli/index.ts +4 -2
  100. package/src/exporters/csv-exporter.ts +304 -0
  101. package/src/exporters/feature-parser.ts +168 -0
  102. package/src/exporters/package-info.ts +35 -0
  103. package/src/exporters/playwright-report-parser.ts +168 -0
  104. package/src/exporters/scenario-merger.ts +63 -0
  105. package/src/exporters/spec-parser.ts +247 -0
  106. package/src/exporters/step-formatter.ts +80 -0
  107. package/src/exporters/test-data-resolver.ts +59 -0
  108. package/src/exporters/types.ts +112 -0
  109. package/src/exporters/xlsx-exporter.ts +301 -0
  110. package/src/generators/test-generator/utils/selector-resolver.ts +26 -0
  111. package/src/orchestrator/ai-rules-updater.ts +12 -0
  112. package/src/orchestrator/project-initializer.ts +103 -70
  113. package/src/orchestrator/screen-manager.ts +5 -2
  114. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +18 -9
  115. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +7 -5
  116. package/src/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +71 -0
  117. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +38 -10
  118. package/src/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  119. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +142 -0
  120. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +100 -0
  121. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +73 -0
  122. package/src/orchestrator/templates/ai-instructions/claude-skill-delivery.md +103 -0
  123. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +2 -0
  124. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +87 -4
  125. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +22 -0
  126. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +18 -9
  127. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +6 -4
  128. package/src/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +71 -0
  129. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +45 -20
  130. package/src/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  131. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +142 -0
  132. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +100 -0
  133. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +73 -0
  134. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +103 -0
  135. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +2 -0
  136. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +87 -4
  137. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +22 -0
  138. package/src/orchestrator/templates/playwright.config.ts +6 -1
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Convert raw Gherkin step text OR generated .spec.ts comment lines into
4
+ * concise, numbered natural language for the CSV Steps/Expected columns.
5
+ *
6
+ * Deterministic — no AI calls.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.formatNumberedSteps = formatNumberedSteps;
10
+ exports.cleanStepLine = cleanStepLine;
11
+ exports.formatPrecondition = formatPrecondition;
12
+ /**
13
+ * Format a list of raw step lines for the Steps / Expected Results columns.
14
+ *
15
+ * - 0 lines → empty string
16
+ * - 1 line → the line verbatim (no "1. " prefix — avoids Google Sheets clutter)
17
+ * - ≥ 2 → each line on its own row, "1. ", "2. ", … prefixes, newline-joined
18
+ * so spreadsheet cells auto-wrap one step per visual line.
19
+ */
20
+ function formatNumberedSteps(lines) {
21
+ const cleaned = lines.map(cleanStepLine).filter((l) => l.length > 0);
22
+ if (cleaned.length === 0)
23
+ return '';
24
+ if (cleaned.length === 1)
25
+ return cleaned[0];
26
+ return cleaned.map((line, idx) => `${idx + 1}. ${line}`).join('\n');
27
+ }
28
+ /**
29
+ * Clean a raw step line (either Gherkin text or .spec.ts comment).
30
+ *
31
+ * Handles patterns like:
32
+ * "User click [login] button" → "Click 'login' button"
33
+ * "User fill [Email] field with {{email}}" → "Fill 'Email' field with {{email}}"
34
+ * "Click Signature 2025 Creator" → "Click 'Signature 2025 Creator'"
35
+ * "Assert title error has text err_xxx" → "Title error has text err_xxx"
36
+ * "Open awards page" → "Open awards page"
37
+ */
38
+ function cleanStepLine(raw) {
39
+ let s = raw.trim();
40
+ // Strip leading "User " actor
41
+ s = s.replace(/^User\s+/i, '');
42
+ // Strip Gherkin-style element decoration "[Ref] type" → "'Ref' type"
43
+ // e.g., "click [Login] button" → "click 'Login' button"
44
+ s = s.replace(/\[([^\]]+)\]/g, "'$1'");
45
+ // Collapse multiple spaces
46
+ s = s.replace(/\s+/g, ' ');
47
+ // For .spec.ts comments that start with "Assert ..." keep as-is (they read naturally)
48
+ // For action comments like "Click X", "Fill X with Y" keep as-is.
49
+ // Capitalize first letter
50
+ if (s.length > 0)
51
+ s = s.charAt(0).toUpperCase() + s.slice(1);
52
+ return s;
53
+ }
54
+ /**
55
+ * Natural language for Given → Pre-condition.
56
+ * Combines auth info + Given steps into a single sentence.
57
+ */
58
+ function formatPrecondition(authRole, givenLines) {
59
+ const parts = [];
60
+ // Auth prefix
61
+ if (authRole === 'no-auth') {
62
+ parts.push('Not authenticated.');
63
+ }
64
+ else if (authRole) {
65
+ parts.push(`Logged in as ${authRole}.`);
66
+ }
67
+ // Given lines (clean + period-separated)
68
+ for (const line of givenLines) {
69
+ const cleaned = cleanStepLine(line);
70
+ if (!cleaned)
71
+ continue;
72
+ parts.push(cleaned.endsWith('.') ? cleaned : cleaned + '.');
73
+ }
74
+ return parts.join(' ').trim();
75
+ }
76
+ //# sourceMappingURL=step-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-formatter.js","sourceRoot":"","sources":["../../src/exporters/step-formatter.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAUH,kDAKC;AAYD,sCAoBC;AAMD,gDAqBC;AAxED;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CAAC,KAAe;IACjD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAEnB,8BAA8B;IAC9B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAE/B,qEAAqE;IACrE,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAEvC,2BAA2B;IAC3B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE3B,sFAAsF;IACtF,kEAAkE;IAElE,0BAA0B;IAC1B,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7D,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAChC,QAAuB,EACvB,UAAoB;IAEpB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,cAAc;IACd,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACnC,CAAC;SAAM,IAAI,QAAQ,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,gBAAgB,QAAQ,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,yCAAyC;IACzC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Resolve test-data.yaml variables for the CSV Test Data column.
3
+ */
4
+ /**
5
+ * Load test-data.yaml into a flat key→value map.
6
+ * Returns empty map if file missing.
7
+ */
8
+ export declare function loadTestData(testDataFilePath: string): Record<string, string>;
9
+ /**
10
+ * Format a list of variable references into a "key: value; key2: value2" string
11
+ * suitable for the CSV Test Data column.
12
+ *
13
+ * Long values (>80 chars) are truncated with "…".
14
+ */
15
+ export declare function formatTestData(referencedVars: string[], testData: Record<string, string>): string;
16
+ /**
17
+ * Resolve the test-data file path for a given screen.
18
+ */
19
+ export declare function resolveTestDataPath(cwd: string, screen: string): string;
20
+ //# sourceMappingURL=test-data-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-data-resolver.d.ts","sourceRoot":"","sources":["../../src/exporters/test-data-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc7E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,MAAM,EAAE,EACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CASR;AAOD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvE"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ /**
3
+ * Resolve test-data.yaml variables for the CSV Test Data column.
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.loadTestData = loadTestData;
40
+ exports.formatTestData = formatTestData;
41
+ exports.resolveTestDataPath = resolveTestDataPath;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const yaml_1 = require("yaml");
45
+ /**
46
+ * Load test-data.yaml into a flat key→value map.
47
+ * Returns empty map if file missing.
48
+ */
49
+ function loadTestData(testDataFilePath) {
50
+ if (!fs.existsSync(testDataFilePath))
51
+ return {};
52
+ const content = fs.readFileSync(testDataFilePath, 'utf-8');
53
+ const parsed = (0, yaml_1.parse)(content);
54
+ if (!parsed || typeof parsed !== 'object')
55
+ return {};
56
+ // Flatten shallow object to string values
57
+ const result = {};
58
+ for (const [key, value] of Object.entries(parsed)) {
59
+ if (value === null || value === undefined)
60
+ continue;
61
+ if (typeof value === 'object')
62
+ continue; // skip nested structures
63
+ result[key] = String(value);
64
+ }
65
+ return result;
66
+ }
67
+ /**
68
+ * Format a list of variable references into a "key: value; key2: value2" string
69
+ * suitable for the CSV Test Data column.
70
+ *
71
+ * Long values (>80 chars) are truncated with "…".
72
+ */
73
+ function formatTestData(referencedVars, testData) {
74
+ if (referencedVars.length === 0)
75
+ return '';
76
+ const pairs = [];
77
+ for (const key of referencedVars) {
78
+ const value = testData[key];
79
+ if (value === undefined)
80
+ continue;
81
+ pairs.push(`${key}: ${truncate(value, 80)}`);
82
+ }
83
+ return pairs.join('; ');
84
+ }
85
+ function truncate(s, max) {
86
+ if (s.length <= max)
87
+ return s;
88
+ return s.substring(0, max - 1) + '…';
89
+ }
90
+ /**
91
+ * Resolve the test-data file path for a given screen.
92
+ */
93
+ function resolveTestDataPath(cwd, screen) {
94
+ return path.join(cwd, 'qa', 'screens', screen, 'test-data', `${screen}.yaml`);
95
+ }
96
+ //# sourceMappingURL=test-data-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-data-resolver.js","sourceRoot":"","sources":["../../src/exporters/test-data-resolver.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUH,oCAcC;AAQD,wCAYC;AAUD,kDAEC;AAtDD,uCAAyB;AACzB,2CAA6B;AAC7B,+BAA0C;AAE1C;;;GAGG;AACH,SAAgB,YAAY,CAAC,gBAAwB;IACnD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAA,YAAS,EAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAErD,0CAA0C;IAC1C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;QAC7E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QACpD,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS,CAAC,yBAAyB;QAClE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAC5B,cAAwB,EACxB,QAAgC;IAEhC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,GAAW;IACtC,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,GAAW,EAAE,MAAc;IAC7D,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Shared types for the delivery exporter.
3
+ */
4
+ /**
5
+ * Test case row in the final CSV output.
6
+ */
7
+ export interface TestCaseRow {
8
+ tcId: string;
9
+ category1: string;
10
+ category2: string;
11
+ category3: string;
12
+ category4: string;
13
+ precondition: string;
14
+ testData: string;
15
+ steps: string;
16
+ expectedResults: string;
17
+ priority: string;
18
+ testcaseType: string;
19
+ testResult: string;
20
+ executedDate: string;
21
+ testExecutor: string;
22
+ testEnvironment: string;
23
+ note: string;
24
+ }
25
+ /**
26
+ * Summary stats per screen.
27
+ */
28
+ export interface ScreenSummary {
29
+ screen: string;
30
+ total: number;
31
+ passed: number;
32
+ failed: number;
33
+ pending: number;
34
+ na: number;
35
+ notCompiled: number;
36
+ outputFile: string;
37
+ }
38
+ /**
39
+ * Pre-flight check result for a single screen.
40
+ */
41
+ export interface PreflightCheck {
42
+ screen: string;
43
+ featureOk: boolean;
44
+ testDataOk: boolean;
45
+ selectorsOk: boolean;
46
+ specOk: boolean;
47
+ resultsOk: boolean;
48
+ missing: string[];
49
+ suggestions: string[];
50
+ }
51
+ /**
52
+ * Metadata extracted from a .feature file.
53
+ */
54
+ export interface FeatureMetadata {
55
+ featureName: string;
56
+ featurePath?: string;
57
+ featureTags: string[];
58
+ scenarios: ScenarioMetadata[];
59
+ }
60
+ export interface ScenarioMetadata {
61
+ name: string;
62
+ tags: string[];
63
+ stepsName?: string;
64
+ extendsName?: string;
65
+ referencedVars: string[];
66
+ rawGivenSteps: string[];
67
+ rawWhenSteps: string[];
68
+ rawThenSteps: string[];
69
+ }
70
+ /**
71
+ * Structure extracted from a compiled .spec.ts test block.
72
+ */
73
+ export interface SpecTest {
74
+ describeName: string;
75
+ authRole?: string;
76
+ testTitle: string;
77
+ scenarioName: string;
78
+ vpId?: string;
79
+ precondition: string[];
80
+ steps: string[];
81
+ expectations: string[];
82
+ }
83
+ export interface SpecFileData {
84
+ tests: SpecTest[];
85
+ }
86
+ /**
87
+ * Result from results.json per test.
88
+ */
89
+ export interface PlaywrightResult {
90
+ testTitle: string;
91
+ status: 'passed' | 'failed' | 'skipped' | 'timedOut' | 'interrupted' | 'unknown';
92
+ startTime?: string;
93
+ error?: string;
94
+ tracePath?: string;
95
+ }
96
+ /**
97
+ * Environment metadata.
98
+ */
99
+ export interface EnvironmentInfo {
100
+ baseURL: string;
101
+ projectName: string;
102
+ executor: string;
103
+ }
104
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/exporters/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the delivery exporter.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/exporters/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Render the same rows/summary the CSV exporter produces into a styled .xlsx
3
+ * workbook. Keeps the BM-2-901-13 layout but adds:
4
+ * - bold header row with filled background + white font
5
+ * - borders on the data region
6
+ * - text wrapping in Steps / Expected / Pre-condition / Test Data
7
+ * - frozen header so the first data rows stay aligned with the title row
8
+ * - sensible column widths
9
+ * - category-separator rows rendered as a filled bar spanning the table
10
+ */
11
+ import ExcelJS from 'exceljs';
12
+ import { ScreenSummary, TestCaseRow } from './types';
13
+ export declare function renderXlsx(summary: ScreenSummary, rows: TestCaseRow[], specLink: string): ExcelJS.Workbook;
14
+ /**
15
+ * Write the workbook to `qa/deliverables/<screen>-testcases.xlsx`.
16
+ * Directory is created on demand. Returns the absolute output path.
17
+ */
18
+ export declare function writeXlsx(cwd: string, screen: string, wb: ExcelJS.Workbook): Promise<string>;
19
+ //# sourceMappingURL=xlsx-exporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xlsx-exporter.d.ts","sourceRoot":"","sources":["../../src/exporters/xlsx-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAsBrD,wBAAgB,UAAU,CACxB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,WAAW,EAAE,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,CAiPlB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,OAAO,CAAC,QAAQ,GACnB,OAAO,CAAC,MAAM,CAAC,CAMjB"}
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ /**
3
+ * Render the same rows/summary the CSV exporter produces into a styled .xlsx
4
+ * workbook. Keeps the BM-2-901-13 layout but adds:
5
+ * - bold header row with filled background + white font
6
+ * - borders on the data region
7
+ * - text wrapping in Steps / Expected / Pre-condition / Test Data
8
+ * - frozen header so the first data rows stay aligned with the title row
9
+ * - sensible column widths
10
+ * - category-separator rows rendered as a filled bar spanning the table
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.renderXlsx = renderXlsx;
50
+ exports.writeXlsx = writeXlsx;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const exceljs_1 = __importDefault(require("exceljs"));
54
+ const package_info_1 = require("./package-info");
55
+ const COL_COUNT = 16;
56
+ const HEADER_FILL = 'FF1F4E78'; // deep blue band
57
+ const HEADER_FONT = 'FFFFFFFF';
58
+ const META_FILL = 'FFDCE6F1'; // soft blue for meta rows
59
+ const CATEGORY_FILL = 'FFFFF2CC'; // soft yellow for group dividers
60
+ const BORDER_COLOR = 'FFBFBFBF';
61
+ function applyBorder(cell) {
62
+ cell.border = {
63
+ top: { style: 'thin', color: { argb: BORDER_COLOR } },
64
+ left: { style: 'thin', color: { argb: BORDER_COLOR } },
65
+ bottom: { style: 'thin', color: { argb: BORDER_COLOR } },
66
+ right: { style: 'thin', color: { argb: BORDER_COLOR } },
67
+ };
68
+ }
69
+ function renderXlsx(summary, rows, specLink) {
70
+ const wb = new exceljs_1.default.Workbook();
71
+ wb.creator = 'sungen delivery';
72
+ wb.created = new Date();
73
+ const ws = wb.addWorksheet('Testcases', {
74
+ views: [{ state: 'frozen', ySplit: 0, xSplit: 0 }],
75
+ });
76
+ const issueDate = (() => {
77
+ const d = new Date();
78
+ return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()}`;
79
+ })();
80
+ const total = summary.total || 1;
81
+ const pct = (n) => `${Math.round((n / total) * 100)}%`;
82
+ // -- Column widths (matches CSV column order) --
83
+ ws.columns = [
84
+ { width: 18 }, // TC ID
85
+ { width: 42 }, // Category 1
86
+ { width: 14 }, // Category 2
87
+ { width: 26 }, // Category 3
88
+ { width: 14 }, // Category 4
89
+ { width: 36 }, // Pre-condition
90
+ { width: 30 }, // Test Data
91
+ { width: 46 }, // Steps
92
+ { width: 52 }, // Expected results
93
+ { width: 10 }, // Priority
94
+ { width: 14 }, // Testcase type
95
+ { width: 14 }, // Test Result
96
+ { width: 14 }, // Executed Date
97
+ { width: 16 }, // Test Executor
98
+ { width: 38 }, // Test Environment
99
+ { width: 40 }, // Note
100
+ ];
101
+ // -- Top metadata band (rows 1-4) --
102
+ const titleLabel = `${summary.screen.toUpperCase()} TESTCASE`;
103
+ const titleRow = ws.addRow(['', '', '', titleLabel, '', '', 'No: BM-2-901-13']);
104
+ titleRow.getCell(4).font = { bold: true, size: 16 };
105
+ titleRow.getCell(4).alignment = { horizontal: 'center', vertical: 'middle' };
106
+ ws.mergeCells(titleRow.number, 4, titleRow.number, 6);
107
+ titleRow.getCell(7).font = { bold: true };
108
+ titleRow.height = 22;
109
+ const versionRow = ws.addRow(['', '', '', '', '', '', `Version: ${(0, package_info_1.getPackageVersion)()}`]);
110
+ versionRow.getCell(7).font = { bold: true };
111
+ const dateRow = ws.addRow(['', '', '', '', '', '', `Issue Date: ${issueDate}`]);
112
+ dateRow.getCell(7).font = { bold: true };
113
+ const companyRow = ws.addRow([
114
+ 'SUN ASTERISK VIETNAM CO., LTD',
115
+ '',
116
+ '',
117
+ '',
118
+ '',
119
+ '',
120
+ 'ISO/IEC 27001:2022 & ISO 9001:2015',
121
+ ]);
122
+ companyRow.getCell(1).font = { bold: true };
123
+ companyRow.getCell(7).font = { bold: true };
124
+ ws.addRow([]); // spacer
125
+ // -- Summary band --
126
+ const summaryHeader = ws.addRow([
127
+ '',
128
+ '',
129
+ 'Total TCs',
130
+ 'Passed',
131
+ 'Failed',
132
+ 'Pending',
133
+ 'N/A',
134
+ 'Remaining',
135
+ ]);
136
+ for (let i = 3; i <= 8; i++) {
137
+ const c = summaryHeader.getCell(i);
138
+ c.font = { bold: true, color: { argb: HEADER_FONT } };
139
+ c.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: HEADER_FILL } };
140
+ c.alignment = { horizontal: 'center', vertical: 'middle' };
141
+ applyBorder(c);
142
+ }
143
+ const summaryCounts = ws.addRow([
144
+ '',
145
+ '',
146
+ summary.total,
147
+ summary.passed,
148
+ summary.failed,
149
+ summary.pending,
150
+ summary.na,
151
+ summary.pending + summary.na,
152
+ ]);
153
+ for (let i = 3; i <= 8; i++) {
154
+ const c = summaryCounts.getCell(i);
155
+ c.font = { bold: true };
156
+ c.alignment = { horizontal: 'center' };
157
+ c.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: META_FILL } };
158
+ applyBorder(c);
159
+ }
160
+ const summaryPct = ws.addRow([
161
+ '',
162
+ '',
163
+ '',
164
+ pct(summary.passed),
165
+ pct(summary.failed),
166
+ pct(summary.pending),
167
+ pct(summary.na),
168
+ pct(summary.pending + summary.na),
169
+ ]);
170
+ for (let i = 4; i <= 8; i++) {
171
+ const c = summaryPct.getCell(i);
172
+ c.alignment = { horizontal: 'center' };
173
+ c.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: META_FILL } };
174
+ applyBorder(c);
175
+ }
176
+ ws.addRow([]); // spacer
177
+ const specRow = ws.addRow(['Spec/Design link:', specLink]);
178
+ specRow.getCell(1).font = { bold: true };
179
+ specRow.getCell(2).font = { color: { argb: 'FF1F4E78' }, underline: true };
180
+ ws.addRow([]); // spacer
181
+ const legendRow = ws.addRow(['*: Mandatory']);
182
+ legendRow.getCell(1).font = { italic: true, color: { argb: 'FF808080' } };
183
+ // -- Column header row (bold, filled, wrapped) --
184
+ const headerRow = ws.addRow([
185
+ 'TC ID*',
186
+ '{Category 1}',
187
+ '{Category 2}',
188
+ '{Category 3}',
189
+ '{Category 4}',
190
+ 'Pre-condition',
191
+ 'Test Data',
192
+ 'Steps*',
193
+ 'Expected results*',
194
+ 'Priority',
195
+ 'Testcase type',
196
+ 'Test Result*',
197
+ 'Executed Date*',
198
+ 'Test Executor*',
199
+ 'Test Environment',
200
+ 'Note\n(Test evidence, DefectID, Actual result)',
201
+ ]);
202
+ headerRow.height = 38;
203
+ headerRow.eachCell((cell) => {
204
+ cell.font = { bold: true, color: { argb: HEADER_FONT } };
205
+ cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: HEADER_FILL } };
206
+ cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
207
+ applyBorder(cell);
208
+ });
209
+ // Freeze everything above and below the header row — reveal header when scrolling.
210
+ ws.views = [{ state: 'frozen', ySplit: headerRow.number }];
211
+ // -- Data rows grouped by category --
212
+ const order = ['Accessing', 'GUI', 'Function'];
213
+ const grouped = new Map();
214
+ for (const r of rows) {
215
+ const g = grouped.get(r.category2) || [];
216
+ g.push(r);
217
+ grouped.set(r.category2, g);
218
+ }
219
+ const emittedGroups = new Set();
220
+ function emitGroup(groupName, groupRows) {
221
+ const divider = ws.addRow(['', groupName]);
222
+ divider.getCell(2).font = { bold: true };
223
+ divider.eachCell({ includeEmpty: false }, (cell) => {
224
+ cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: CATEGORY_FILL } };
225
+ });
226
+ // Fill the full width so the band spans the whole table
227
+ for (let i = 1; i <= COL_COUNT; i++) {
228
+ const c = divider.getCell(i);
229
+ c.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: CATEGORY_FILL } };
230
+ applyBorder(c);
231
+ }
232
+ for (const r of groupRows) {
233
+ const row = ws.addRow([
234
+ r.tcId,
235
+ r.category1,
236
+ '',
237
+ '',
238
+ '',
239
+ r.precondition,
240
+ r.testData,
241
+ r.steps,
242
+ r.expectedResults,
243
+ r.priority,
244
+ r.testcaseType,
245
+ r.testResult,
246
+ r.executedDate,
247
+ r.testExecutor,
248
+ r.testEnvironment,
249
+ r.note,
250
+ ]);
251
+ row.alignment = { vertical: 'top', wrapText: true };
252
+ row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
253
+ applyBorder(cell);
254
+ if (colNumber === 1) {
255
+ cell.font = { bold: true };
256
+ }
257
+ if (colNumber === 12) {
258
+ // Test Result — colour-code
259
+ const val = String(cell.value || '');
260
+ if (val === 'Passed') {
261
+ cell.font = { color: { argb: 'FF107C41' }, bold: true };
262
+ }
263
+ else if (val === 'Failed') {
264
+ cell.font = { color: { argb: 'FFC00000' }, bold: true };
265
+ }
266
+ else if (val === 'Pending') {
267
+ cell.font = { color: { argb: 'FF996D00' }, bold: true };
268
+ }
269
+ else if (val === 'N/A') {
270
+ cell.font = { color: { argb: 'FF808080' } };
271
+ }
272
+ }
273
+ });
274
+ }
275
+ }
276
+ for (const groupName of order) {
277
+ const groupRows = grouped.get(groupName);
278
+ if (!groupRows || groupRows.length === 0)
279
+ continue;
280
+ emittedGroups.add(groupName);
281
+ emitGroup(groupName, groupRows);
282
+ }
283
+ for (const [groupName, groupRows] of grouped.entries()) {
284
+ if (emittedGroups.has(groupName))
285
+ continue;
286
+ emitGroup(groupName, groupRows);
287
+ }
288
+ // Auto-filter on the header row so QA can filter by result / priority / category
289
+ ws.autoFilter = {
290
+ from: { row: headerRow.number, column: 1 },
291
+ to: { row: ws.rowCount, column: COL_COUNT },
292
+ };
293
+ return wb;
294
+ }
295
+ /**
296
+ * Write the workbook to `qa/deliverables/<screen>-testcases.xlsx`.
297
+ * Directory is created on demand. Returns the absolute output path.
298
+ */
299
+ async function writeXlsx(cwd, screen, wb) {
300
+ const outDir = path.join(cwd, 'qa', 'deliverables');
301
+ if (!fs.existsSync(outDir))
302
+ fs.mkdirSync(outDir, { recursive: true });
303
+ const outPath = path.join(outDir, `${screen}-testcases.xlsx`);
304
+ await wb.xlsx.writeFile(outPath);
305
+ return outPath;
306
+ }
307
+ void applyBorder;
308
+ void {};
309
+ //# sourceMappingURL=xlsx-exporter.js.map