@sun-asterisk/sungen 3.1.0 → 3.1.2-beta.100

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 (228) hide show
  1. package/README.md +4 -428
  2. package/dist/capabilities/builtins.d.ts +31 -0
  3. package/dist/capabilities/builtins.d.ts.map +1 -0
  4. package/dist/capabilities/builtins.js +84 -0
  5. package/dist/capabilities/builtins.js.map +1 -0
  6. package/dist/capabilities/context-router.d.ts +34 -0
  7. package/dist/capabilities/context-router.d.ts.map +1 -0
  8. package/dist/capabilities/context-router.js +49 -0
  9. package/dist/capabilities/context-router.js.map +1 -0
  10. package/dist/capabilities/context.d.ts +51 -0
  11. package/dist/capabilities/context.d.ts.map +1 -0
  12. package/dist/capabilities/context.js +17 -0
  13. package/dist/capabilities/context.js.map +1 -0
  14. package/dist/capabilities/discover.d.ts +2 -0
  15. package/dist/capabilities/discover.d.ts.map +1 -0
  16. package/dist/capabilities/discover.js +48 -0
  17. package/dist/capabilities/discover.js.map +1 -0
  18. package/dist/capabilities/registry.d.ts +90 -0
  19. package/dist/capabilities/registry.d.ts.map +1 -0
  20. package/dist/capabilities/registry.js +43 -0
  21. package/dist/capabilities/registry.js.map +1 -0
  22. package/dist/capabilities/sensor.d.ts +49 -0
  23. package/dist/capabilities/sensor.d.ts.map +1 -0
  24. package/dist/capabilities/sensor.js +3 -0
  25. package/dist/capabilities/sensor.js.map +1 -0
  26. package/dist/cli/commands/challenge.d.ts.map +1 -1
  27. package/dist/cli/commands/challenge.js +9 -2
  28. package/dist/cli/commands/challenge.js.map +1 -1
  29. package/dist/cli/commands/delivery.d.ts.map +1 -1
  30. package/dist/cli/commands/delivery.js +3 -2
  31. package/dist/cli/commands/delivery.js.map +1 -1
  32. package/dist/cli/commands/generate.d.ts.map +1 -1
  33. package/dist/cli/commands/generate.js +12 -0
  34. package/dist/cli/commands/generate.js.map +1 -1
  35. package/dist/cli/index.js +10 -1
  36. package/dist/cli/index.js.map +1 -1
  37. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  38. package/dist/exporters/csv-exporter.js +92 -76
  39. package/dist/exporters/csv-exporter.js.map +1 -1
  40. package/dist/exporters/spec-parser.d.ts.map +1 -1
  41. package/dist/exporters/spec-parser.js +6 -1
  42. package/dist/exporters/spec-parser.js.map +1 -1
  43. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +2 -0
  44. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  45. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +1 -0
  46. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  47. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  48. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  49. package/dist/generators/test-generator/adapters/playwright/templates/scenario.hbs +19 -1
  50. package/dist/generators/test-generator/code-generator.d.ts +21 -4
  51. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  52. package/dist/generators/test-generator/code-generator.js +118 -57
  53. package/dist/generators/test-generator/code-generator.js.map +1 -1
  54. package/dist/generators/test-generator/patterns/expect-patterns.d.ts +3 -0
  55. package/dist/generators/test-generator/patterns/expect-patterns.d.ts.map +1 -0
  56. package/dist/generators/test-generator/patterns/expect-patterns.js +54 -0
  57. package/dist/generators/test-generator/patterns/expect-patterns.js.map +1 -0
  58. package/dist/generators/test-generator/patterns/index.d.ts +0 -10
  59. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  60. package/dist/generators/test-generator/patterns/index.js +10 -45
  61. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  62. package/dist/generators/test-generator/step-mapper.d.ts +6 -0
  63. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  64. package/dist/generators/test-generator/step-mapper.js +8 -0
  65. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  66. package/dist/generators/test-generator/template-engine.d.ts +4 -0
  67. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  68. package/dist/generators/test-generator/template-engine.js +1 -1
  69. package/dist/generators/test-generator/template-engine.js.map +1 -1
  70. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts +1 -1
  71. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -1
  72. package/dist/generators/test-generator/utils/runtime-data-transformer.js +5 -5
  73. package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -1
  74. package/dist/harness/annotation-overrides.d.ts +9 -0
  75. package/dist/harness/annotation-overrides.d.ts.map +1 -0
  76. package/dist/harness/annotation-overrides.js +36 -0
  77. package/dist/harness/annotation-overrides.js.map +1 -0
  78. package/dist/harness/audit.d.ts.map +1 -1
  79. package/dist/harness/audit.js +35 -7
  80. package/dist/harness/audit.js.map +1 -1
  81. package/dist/harness/catalog/drivers.yaml +35 -12
  82. package/dist/harness/challenge.d.ts +1 -0
  83. package/dist/harness/challenge.d.ts.map +1 -1
  84. package/dist/harness/challenge.js +49 -2
  85. package/dist/harness/challenge.js.map +1 -1
  86. package/dist/harness/data-driven-lint.d.ts +7 -0
  87. package/dist/harness/data-driven-lint.d.ts.map +1 -0
  88. package/dist/harness/data-driven-lint.js +153 -0
  89. package/dist/harness/data-driven-lint.js.map +1 -0
  90. package/dist/harness/parse.d.ts +3 -0
  91. package/dist/harness/parse.d.ts.map +1 -1
  92. package/dist/harness/parse.js +25 -0
  93. package/dist/harness/parse.js.map +1 -1
  94. package/dist/harness/query-catalog.d.ts +48 -0
  95. package/dist/harness/query-catalog.d.ts.map +1 -0
  96. package/dist/harness/query-catalog.js +0 -0
  97. package/dist/harness/query-catalog.js.map +1 -0
  98. package/dist/harness/script-check.d.ts.map +1 -1
  99. package/dist/harness/script-check.js +7 -4
  100. package/dist/harness/script-check.js.map +1 -1
  101. package/dist/index.d.ts +20 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +32 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/orchestrator/templates/ai-instructions/claude-agent-challenge.md +3 -2
  106. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +4 -3
  107. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +41 -0
  108. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +22 -0
  109. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +1 -0
  110. package/dist/orchestrator/templates/ai-instructions/claude-skill-test-design-techniques.md +6 -0
  111. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +4 -3
  112. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +41 -0
  113. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +22 -0
  114. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +1 -0
  115. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-test-design-techniques.md +6 -0
  116. package/dist/orchestrator/templates/specs-api.d.ts +19 -0
  117. package/dist/orchestrator/templates/specs-api.d.ts.map +1 -0
  118. package/dist/orchestrator/templates/specs-api.js +128 -0
  119. package/dist/orchestrator/templates/specs-api.js.map +1 -0
  120. package/dist/orchestrator/templates/specs-api.ts +101 -0
  121. package/dist/orchestrator/templates/specs-db.d.ts +8 -0
  122. package/dist/orchestrator/templates/specs-db.d.ts.map +1 -1
  123. package/dist/orchestrator/templates/specs-db.js +22 -0
  124. package/dist/orchestrator/templates/specs-db.js.map +1 -1
  125. package/dist/orchestrator/templates/specs-db.ts +22 -0
  126. package/dist/orchestrator/templates/specs-test-data.ts +76 -15
  127. package/package.json +7 -30
  128. package/src/capabilities/builtins.ts +85 -0
  129. package/src/capabilities/context-router.ts +66 -0
  130. package/src/capabilities/context.ts +46 -0
  131. package/src/capabilities/discover.ts +42 -0
  132. package/src/capabilities/registry.ts +111 -0
  133. package/src/capabilities/sensor.ts +47 -0
  134. package/src/cli/commands/challenge.ts +6 -2
  135. package/src/cli/commands/delivery.ts +3 -2
  136. package/src/cli/commands/generate.ts +12 -0
  137. package/src/cli/index.ts +10 -1
  138. package/src/exporters/csv-exporter.ts +22 -6
  139. package/src/exporters/spec-parser.ts +6 -1
  140. package/src/generators/test-generator/adapters/adapter-interface.ts +2 -1
  141. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +1 -1
  142. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  143. package/src/generators/test-generator/adapters/playwright/templates/scenario.hbs +19 -1
  144. package/src/generators/test-generator/code-generator.ts +114 -59
  145. package/src/generators/test-generator/patterns/expect-patterns.ts +49 -0
  146. package/src/generators/test-generator/patterns/index.ts +9 -33
  147. package/src/generators/test-generator/step-mapper.ts +9 -0
  148. package/src/generators/test-generator/template-engine.ts +5 -2
  149. package/src/generators/test-generator/utils/runtime-data-transformer.ts +5 -5
  150. package/src/harness/annotation-overrides.ts +25 -0
  151. package/src/harness/audit.ts +37 -8
  152. package/src/harness/catalog/drivers.yaml +35 -12
  153. package/src/harness/challenge.ts +47 -2
  154. package/src/harness/data-driven-lint.ts +119 -0
  155. package/src/harness/parse.ts +17 -0
  156. package/src/harness/query-catalog.ts +0 -0
  157. package/src/harness/script-check.ts +8 -5
  158. package/src/index.ts +30 -0
  159. package/src/orchestrator/templates/ai-instructions/claude-agent-challenge.md +3 -2
  160. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +4 -3
  161. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +41 -0
  162. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +22 -0
  163. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +1 -0
  164. package/src/orchestrator/templates/ai-instructions/claude-skill-test-design-techniques.md +6 -0
  165. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +4 -3
  166. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +41 -0
  167. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +22 -0
  168. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +1 -0
  169. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-test-design-techniques.md +6 -0
  170. package/src/orchestrator/templates/specs-api.ts +101 -0
  171. package/src/orchestrator/templates/specs-db.ts +22 -0
  172. package/src/orchestrator/templates/specs-test-data.ts +76 -15
  173. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts +0 -7
  174. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +0 -1
  175. package/dist/generators/test-generator/patterns/assertion-patterns.js +0 -626
  176. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +0 -1
  177. package/dist/generators/test-generator/patterns/capture-patterns.d.ts +0 -21
  178. package/dist/generators/test-generator/patterns/capture-patterns.d.ts.map +0 -1
  179. package/dist/generators/test-generator/patterns/capture-patterns.js +0 -87
  180. package/dist/generators/test-generator/patterns/capture-patterns.js.map +0 -1
  181. package/dist/generators/test-generator/patterns/database-patterns.d.ts +0 -5
  182. package/dist/generators/test-generator/patterns/database-patterns.d.ts.map +0 -1
  183. package/dist/generators/test-generator/patterns/database-patterns.js +0 -94
  184. package/dist/generators/test-generator/patterns/database-patterns.js.map +0 -1
  185. package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -6
  186. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +0 -1
  187. package/dist/generators/test-generator/patterns/form-patterns.js +0 -160
  188. package/dist/generators/test-generator/patterns/form-patterns.js.map +0 -1
  189. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -6
  190. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +0 -1
  191. package/dist/generators/test-generator/patterns/interaction-patterns.js +0 -433
  192. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +0 -1
  193. package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts +0 -7
  194. package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts.map +0 -1
  195. package/dist/generators/test-generator/patterns/keyboard-patterns.js +0 -47
  196. package/dist/generators/test-generator/patterns/keyboard-patterns.js.map +0 -1
  197. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -6
  198. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +0 -1
  199. package/dist/generators/test-generator/patterns/navigation-patterns.js +0 -125
  200. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +0 -1
  201. package/dist/generators/test-generator/patterns/scope-patterns.d.ts +0 -7
  202. package/dist/generators/test-generator/patterns/scope-patterns.d.ts.map +0 -1
  203. package/dist/generators/test-generator/patterns/scope-patterns.js +0 -36
  204. package/dist/generators/test-generator/patterns/scope-patterns.js.map +0 -1
  205. package/dist/generators/test-generator/patterns/scroll-patterns.d.ts +0 -7
  206. package/dist/generators/test-generator/patterns/scroll-patterns.d.ts.map +0 -1
  207. package/dist/generators/test-generator/patterns/scroll-patterns.js +0 -25
  208. package/dist/generators/test-generator/patterns/scroll-patterns.js.map +0 -1
  209. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -6
  210. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +0 -1
  211. package/dist/generators/test-generator/patterns/setup-patterns.js +0 -72
  212. package/dist/generators/test-generator/patterns/setup-patterns.js.map +0 -1
  213. package/dist/generators/test-generator/patterns/table-patterns.d.ts +0 -19
  214. package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +0 -1
  215. package/dist/generators/test-generator/patterns/table-patterns.js +0 -239
  216. package/dist/generators/test-generator/patterns/table-patterns.js.map +0 -1
  217. package/docs/orchestration-spec.md +0 -267
  218. package/src/generators/test-generator/patterns/assertion-patterns.ts +0 -691
  219. package/src/generators/test-generator/patterns/capture-patterns.ts +0 -97
  220. package/src/generators/test-generator/patterns/database-patterns.ts +0 -95
  221. package/src/generators/test-generator/patterns/form-patterns.ts +0 -167
  222. package/src/generators/test-generator/patterns/interaction-patterns.ts +0 -465
  223. package/src/generators/test-generator/patterns/keyboard-patterns.ts +0 -51
  224. package/src/generators/test-generator/patterns/navigation-patterns.ts +0 -140
  225. package/src/generators/test-generator/patterns/scope-patterns.ts +0 -40
  226. package/src/generators/test-generator/patterns/scroll-patterns.ts +0 -27
  227. package/src/generators/test-generator/patterns/setup-patterns.ts +0 -76
  228. package/src/generators/test-generator/patterns/table-patterns.ts +0 -279
@@ -1,626 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertionPatterns = void 0;
4
- /**
5
- * Assertion patterns: visibility, text content, state, attributes
6
- * Uses template engine for framework-agnostic code generation
7
- */
8
- exports.assertionPatterns = [
9
- // Browser alert text assertion: "see [Are you sure?] alert"
10
- {
11
- name: 'alert-text-assertion',
12
- matcher: (step) => (step.text.includes('see') || step.text.includes('sees')) &&
13
- step.elementType === 'alert' &&
14
- !!step.selectorRef,
15
- resolver: (step, context) => {
16
- let dataValue = step.selectorRef || '';
17
- if (step.dataRef) {
18
- try {
19
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
20
- }
21
- catch {
22
- dataValue = `\${${step.dataRef}}`;
23
- }
24
- }
25
- return {
26
- templateName: 'alert-text-assertion',
27
- data: { dataValue, stepCounter: context.stepCounter },
28
- comment: `Assert browser alert contains "${step.selectorRef}"`,
29
- };
30
- },
31
- priority: 21,
32
- },
33
- // Column cell assertion: "see [Department] column 1 with {{value}}" -> check table cell text
34
- {
35
- name: 'column-cell-assertion',
36
- matcher: (step) => (step.text.includes('should see') || step.text.match(/\b(see|sees)\s+\[/)) &&
37
- !!step.selectorRef &&
38
- !!step.dataRef &&
39
- (step.elementType === 'column' || step.elementType === 'columnheader'),
40
- resolver: (step, context) => {
41
- let dataValue;
42
- try {
43
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
44
- }
45
- catch (error) {
46
- dataValue = `\${${step.dataRef}}`;
47
- }
48
- // getByRole('row') includes header row as nth(0), so Gherkin nth=1 maps to locator nth(1)
49
- const rowNth = step.nth || 1;
50
- // Create a safe variable name from column name
51
- const columnIndexVar = `colIndex${step.selectorRef.replace(/[^a-zA-Z0-9]/g, '')}`;
52
- return {
53
- templateName: 'column-cell-assertion',
54
- data: {
55
- columnName: step.selectorRef,
56
- rowNth,
57
- columnIndexVar,
58
- dataValue,
59
- },
60
- comment: `Assert ${step.selectorRef} column row ${step.nth || 1} has text ${step.dataRef}`,
61
- };
62
- },
63
- priority: 15, // Higher than all other assertion patterns
64
- },
65
- // Page assertion pattern: "see [home] page" -> check URL matches selector value
66
- {
67
- name: 'page-assertion',
68
- matcher: (step) => (step.text.includes('should see') ||
69
- step.text.includes('see') ||
70
- step.text.includes('sees')) &&
71
- step.elementType === 'page',
72
- resolver: (step, context) => {
73
- let path = step.featurePath || '/';
74
- // If selector is present, extract path from selector's value attribute
75
- if (step.selectorRef) {
76
- try {
77
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, context.featureName, step.elementType, step.nth);
78
- // Use selector's value as the path for URL assertion
79
- path = resolved.value || path;
80
- }
81
- catch (error) {
82
- // Fallback to feature path if selector not found
83
- path = step.featurePath || '/';
84
- }
85
- }
86
- // Convert path to regex-safe string
87
- const pathRegex = path.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&');
88
- return {
89
- templateName: 'page-assertion',
90
- data: { pathRegex },
91
- comment: step.selectorRef ? `Assert on ${step.selectorRef} page` : `Assert on page`,
92
- };
93
- },
94
- priority: 13, // Higher priority than general visibility
95
- },
96
- // Pattern: Then User see [panel] dialog with {{kudo.title}} hidden -> toBeHidden()
97
- {
98
- name: 'see-with-variable-hidden',
99
- matcher: (step) => (step.text.includes('should see') || step.text.match(/\b(see|sees)\s+\[/)) &&
100
- !!step.selectorRef &&
101
- !!step.dataRef &&
102
- step.text.includes('with') &&
103
- /\bis hidden\b/.test(step.text),
104
- generator: (step, context) => {
105
- let resolved = {};
106
- try {
107
- resolved = context.selectorResolver.resolveSelector(step.selectorRef, context.featureName, step.elementType, step.nth);
108
- }
109
- catch (error) { }
110
- let dataValue;
111
- try {
112
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
113
- }
114
- catch (error) {
115
- dataValue = `\${${step.dataRef}}`;
116
- }
117
- const escapedVariable = dataValue.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&');
118
- if (resolved.strategy === 'locator') {
119
- const code = context.templateEngine.renderStep('hidden-with-filter-assertion', {
120
- ...resolved, dataValue, nth: resolved.nth,
121
- });
122
- return { code, comment: `Assert ${step.selectorRef} hidden with ${step.dataRef}` };
123
- }
124
- if (resolved.strategy === 'role' && resolved.role) {
125
- // Dialog role: check heading inside dialog instead of filter on full text content
126
- if (resolved.role === 'dialog') {
127
- const code = context.templateEngine.renderStep('hidden-dialog-heading-assertion', {
128
- dataValue,
129
- });
130
- return { code, comment: `Assert ${step.selectorRef} dialog hidden with heading ${step.dataRef}` };
131
- }
132
- const code = context.templateEngine.renderStep('hidden-with-role-variable-assertion', {
133
- role: resolved.role,
134
- name: resolved.name && resolved.name.trim() ? resolved.name : undefined,
135
- dataValue,
136
- nth: resolved.nth,
137
- });
138
- return { code, comment: `Assert ${step.selectorRef} hidden with ${step.dataRef}` };
139
- }
140
- const selectorValue = resolved.value || '';
141
- if (selectorValue && selectorValue.trim()) {
142
- const code = context.templateEngine.renderStep('hidden-with-filter-assertion', {
143
- ...resolved, dataValue, nth: resolved.nth,
144
- });
145
- return { code, comment: `Assert ${step.selectorRef} hidden with ${step.dataRef}` };
146
- }
147
- const code = context.templateEngine.renderStep('hidden-with-variable-assertion', {
148
- selectorRef: step.selectorRef,
149
- selectorValue: resolved.value || '',
150
- dataValue,
151
- nth: resolved.nth,
152
- });
153
- return { code, comment: `Assert ${step.selectorRef} hidden with ${step.dataRef}` };
154
- },
155
- priority: 14,
156
- },
157
- // Pattern: Then User see [submit] button with {{label}} disabled -> toBeDisabled()
158
- {
159
- name: 'see-with-variable-disabled',
160
- matcher: (step) => (step.text.includes('should see') || step.text.match(/\b(see|sees)\s+\[/)) &&
161
- !!step.selectorRef &&
162
- !!step.dataRef &&
163
- step.text.includes('with') &&
164
- /\bis disabled\b/.test(step.text),
165
- generator: (step, context) => {
166
- let resolved = {};
167
- try {
168
- resolved = context.selectorResolver.resolveSelector(step.selectorRef, context.featureName, step.elementType, step.nth);
169
- }
170
- catch (error) { }
171
- let dataValue;
172
- try {
173
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
174
- }
175
- catch (error) {
176
- dataValue = `\${${step.dataRef}}`;
177
- }
178
- const escapedVariable = dataValue.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&');
179
- if (resolved.strategy === 'locator') {
180
- const code = context.templateEngine.renderStep('disabled-with-filter-assertion', {
181
- ...resolved, dataValue, nth: resolved.nth,
182
- });
183
- return { code, comment: `Assert ${step.selectorRef} disabled with ${step.dataRef}` };
184
- }
185
- if (resolved.strategy === 'role' && resolved.role) {
186
- const code = context.templateEngine.renderStep('disabled-with-role-variable-assertion', {
187
- role: resolved.role,
188
- name: resolved.name && resolved.name.trim() ? resolved.name : undefined,
189
- dataValue,
190
- nth: resolved.nth,
191
- });
192
- return { code, comment: `Assert ${step.selectorRef} disabled with ${step.dataRef}` };
193
- }
194
- const selectorValue = resolved.value || '';
195
- if (selectorValue && selectorValue.trim()) {
196
- const code = context.templateEngine.renderStep('disabled-with-filter-assertion', {
197
- ...resolved, dataValue, nth: resolved.nth,
198
- });
199
- return { code, comment: `Assert ${step.selectorRef} disabled with ${step.dataRef}` };
200
- }
201
- const code = context.templateEngine.renderStep('disabled-with-variable-assertion', {
202
- selectorRef: step.selectorRef,
203
- selectorValue: resolved.value || '',
204
- dataValue,
205
- nth: resolved.nth,
206
- });
207
- return { code, comment: `Assert ${step.selectorRef} disabled with ${step.dataRef}` };
208
- },
209
- priority: 14,
210
- },
211
- // NEW: Assertion with variable (handles both empty selector and static + variable)
212
- // Pattern: Then User see [error] message with {{fail_message}}
213
- // If selector YAML has empty value, uses variable-only matching
214
- // If selector has value, combines both (static text + variable)
215
- // Input types → toHaveValue, everything else → toHaveText
216
- {
217
- name: 'see-with-variable',
218
- matcher: (step) => (step.text.includes('should see') ||
219
- step.text.match(/\b(see|sees)\s+\[/)) &&
220
- !!step.selectorRef &&
221
- !!step.dataRef &&
222
- step.text.includes('with'),
223
- generator: (step, context) => {
224
- // Input element types use toHaveValue instead of toHaveText
225
- const INPUT_TYPES = new Set([
226
- 'field', 'textarea', 'search', 'dropdown', 'slider', 'date-picker',
227
- 'input', 'textbox', 'editor', 'select', 'combobox',
228
- ]);
229
- // Resolve data variable value
230
- let dataValue;
231
- try {
232
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
233
- }
234
- catch (error) {
235
- dataValue = `\${${step.dataRef}}`;
236
- }
237
- // Resolve selector from YAML with feature context
238
- let resolved = {};
239
- try {
240
- resolved = context.selectorResolver.resolveSelector(step.selectorRef, context.featureName, step.elementType, step.nth);
241
- }
242
- catch (error) {
243
- // Selector not in YAML or context issue - will use variable-only
244
- }
245
- // --- Attribute assertion: toHaveAttribute ---
246
- // When selector YAML has `attribute` field (e.g., attribute: 'src', 'href')
247
- if (resolved.attribute) {
248
- const code = context.templateEngine.renderStep('attribute-assertion', {
249
- ...resolved,
250
- dataValue,
251
- });
252
- return {
253
- code,
254
- comment: `Assert ${step.selectorRef} ${resolved.attribute} matches ${step.dataRef}`,
255
- };
256
- }
257
- // --- Input types: toHaveValue ---
258
- if (step.elementType && INPUT_TYPES.has(step.elementType)) {
259
- const code = context.templateEngine.renderStep('have-value-assertion', {
260
- ...resolved,
261
- dataValue,
262
- });
263
- return {
264
- code,
265
- comment: `Assert ${step.selectorRef} has value ${step.dataRef}`,
266
- };
267
- }
268
- // --- Label-value pattern: "User see [X] label with {{Y}}" ---
269
- if (step.elementType === 'label' && step.dataRef) {
270
- let label = step.selectorRef;
271
- try {
272
- const labelResolved = context.selectorResolver.resolveSelector(step.selectorRef, context.featureName, step.elementType, step.nth);
273
- if (labelResolved.value !== undefined && labelResolved.value.trim() === '') {
274
- label = undefined;
275
- }
276
- }
277
- catch {
278
- // No selector entry — use label from selectorRef
279
- }
280
- const code = context.templateEngine.renderStep('label-value-assertion', {
281
- label,
282
- dataValue,
283
- });
284
- return {
285
- code,
286
- comment: `Assert ${step.selectorRef} label with value ${step.dataRef}`,
287
- };
288
- }
289
- // --- Dialog role: check heading inside dialog ---
290
- if (resolved.strategy === 'role' && resolved.role === 'dialog') {
291
- const code = context.templateEngine.renderStep('visible-dialog-heading-assertion', {
292
- dataValue,
293
- });
294
- return {
295
- code,
296
- comment: `Assert ${step.selectorRef} dialog with heading ${step.dataRef}`,
297
- };
298
- }
299
- // --- Image role: images have no text, use name ---
300
- if (resolved.strategy === 'role' && resolved.role === 'img') {
301
- const hasName = resolved.name && resolved.name.trim();
302
- const code = context.templateEngine.renderStep('visible-with-role-variable-assertion', {
303
- role: resolved.role,
304
- name: hasName ? resolved.name : dataValue,
305
- exact: resolved.exact || false,
306
- nth: resolved.nth,
307
- });
308
- return {
309
- code,
310
- comment: `Assert ${step.selectorRef} image with name ${step.dataRef}`,
311
- };
312
- }
313
- // --- Everything else: toHaveText (exact full match) ---
314
- // Locator strategy
315
- if (resolved.strategy === 'locator') {
316
- const code = context.templateEngine.renderStep('have-text-assertion', {
317
- ...resolved,
318
- expectedText: dataValue,
319
- });
320
- return {
321
- code,
322
- comment: `Assert ${step.selectorRef} has text ${step.dataRef}`,
323
- };
324
- }
325
- // Role-based selector
326
- if (resolved.strategy === 'role' && resolved.role) {
327
- const hasName = resolved.name && resolved.name.trim();
328
- const code = context.templateEngine.renderStep('have-text-assertion', {
329
- ...resolved,
330
- expectedText: dataValue,
331
- });
332
- return {
333
- code,
334
- comment: `Assert ${step.selectorRef} has text ${step.dataRef}`,
335
- };
336
- }
337
- // Text/placeholder/testid/other strategies
338
- const code = context.templateEngine.renderStep('have-text-assertion', {
339
- ...resolved,
340
- expectedText: dataValue,
341
- });
342
- return {
343
- code,
344
- comment: `Assert ${step.selectorRef} has text ${step.dataRef}`,
345
- };
346
- },
347
- priority: 13,
348
- },
349
- {
350
- name: 'should-be-visible',
351
- matcher: (step) => (step.text.includes('should be visible') ||
352
- step.text.includes('should be displayed') ||
353
- step.text.includes('should see') ||
354
- step.text.match(/\b(see|sees)\s+\[/)) &&
355
- !!step.selectorRef,
356
- resolver: (step, context) => {
357
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
358
- return {
359
- templateName: 'visible-assertion',
360
- data: { ...resolved, selectorRef: step.selectorRef },
361
- comment: `Assert ${step.selectorRef} is visible`,
362
- };
363
- },
364
- priority: 10,
365
- },
366
- {
367
- name: 'is-hidden',
368
- // "see [target] is hidden" — no variable version; with-variable handled by see-with-variable-hidden
369
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis hidden\b/.test(step.text) &&
370
- !step.dataRef && !!step.selectorRef,
371
- resolver: (step, context) => {
372
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
373
- return {
374
- templateName: 'is-hidden-assertion',
375
- data: { ...resolved, selectorRef: step.selectorRef },
376
- comment: `Assert ${step.selectorRef} is not visible`,
377
- };
378
- },
379
- priority: 11,
380
- },
381
- {
382
- name: 'should-be-enabled',
383
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis enabled\b/.test(step.text) && !!step.selectorRef,
384
- resolver: (step, context) => {
385
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
386
- return {
387
- templateName: 'enabled-assertion',
388
- data: { ...resolved, selectorRef: step.selectorRef },
389
- comment: `Assert ${step.selectorRef} is enabled`,
390
- };
391
- },
392
- priority: 11,
393
- },
394
- {
395
- name: 'should-be-disabled',
396
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis disabled\b/.test(step.text) && !!step.selectorRef,
397
- resolver: (step, context) => {
398
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
399
- return {
400
- templateName: 'disabled-assertion',
401
- data: { ...resolved, selectorRef: step.selectorRef },
402
- comment: `Assert ${step.selectorRef} is disabled`,
403
- };
404
- },
405
- priority: 11,
406
- },
407
- {
408
- name: 'should-contain-text',
409
- matcher: (step) => (step.text.includes('should contain') || step.text.includes('contains')) && !!step.selectorRef && !!(step.value || step.dataRef),
410
- resolver: (step, context) => {
411
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
412
- const expectedText = step.value || context.dataResolver.resolveData(step.dataRef, context.featureName);
413
- return {
414
- templateName: 'contain-text-assertion',
415
- data: { ...resolved, expectedText },
416
- comment: `Assert ${step.selectorRef} contains "${step.value || step.dataRef}"`,
417
- };
418
- },
419
- priority: 12,
420
- },
421
- {
422
- name: 'should-have-text',
423
- matcher: (step) => (step.text.includes('should have text') || step.text.includes('has text')) && !!step.selectorRef && !!(step.value || step.dataRef),
424
- resolver: (step, context) => {
425
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
426
- const expectedText = step.value || context.dataResolver.resolveData(step.dataRef, context.featureName);
427
- return {
428
- templateName: 'have-text-assertion',
429
- data: { ...resolved, expectedText },
430
- comment: `Assert ${step.selectorRef} has text "${step.value || step.dataRef}"`,
431
- };
432
- },
433
- priority: 12,
434
- },
435
- {
436
- name: 'is-empty',
437
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis empty\b/.test(step.text) && !!step.selectorRef,
438
- resolver: (step, context) => {
439
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
440
- return {
441
- templateName: 'empty-assertion',
442
- data: { ...resolved, selectorRef: step.selectorRef },
443
- comment: `Assert ${step.selectorRef} is empty`,
444
- };
445
- },
446
- priority: 11,
447
- },
448
- {
449
- name: 'is-checked',
450
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis checked\b/.test(step.text) && !!step.selectorRef,
451
- resolver: (step, context) => {
452
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
453
- return {
454
- templateName: 'checked-assertion',
455
- data: { ...resolved, selectorRef: step.selectorRef },
456
- comment: `Assert ${step.selectorRef} is checked`,
457
- };
458
- },
459
- priority: 11,
460
- },
461
- {
462
- name: 'is-unchecked',
463
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis unchecked\b/.test(step.text) && !!step.selectorRef,
464
- resolver: (step, context) => {
465
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
466
- return {
467
- templateName: 'not-checked-assertion',
468
- data: { ...resolved, selectorRef: step.selectorRef },
469
- comment: `Assert ${step.selectorRef} is unchecked`,
470
- };
471
- },
472
- priority: 11,
473
- },
474
- {
475
- name: 'is-focused',
476
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis focused\b/.test(step.text) && !!step.selectorRef,
477
- resolver: (step, context) => {
478
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
479
- return {
480
- templateName: 'focused-assertion',
481
- data: { ...resolved, selectorRef: step.selectorRef },
482
- comment: `Assert ${step.selectorRef} is focused`,
483
- };
484
- },
485
- priority: 11,
486
- },
487
- {
488
- name: 'see-data-text',
489
- matcher: (step) => (step.text.includes('should see') ||
490
- step.text.match(/\b(see|sees)\b/)) &&
491
- !step.selectorRef &&
492
- !!step.dataRef,
493
- resolver: (step, context) => {
494
- // Resolve data reference to actual value
495
- let dataValue;
496
- try {
497
- dataValue = context.dataResolver.resolveData(step.dataRef, context.featureName);
498
- }
499
- catch (error) {
500
- dataValue = `\${${step.dataRef}}`;
501
- }
502
- return {
503
- templateName: 'visible-assertion',
504
- data: {
505
- strategy: 'text',
506
- value: dataValue,
507
- },
508
- comment: `Assert ${step.dataRef} is visible`,
509
- };
510
- },
511
- priority: 5, // Lower than selector-based assertions
512
- },
513
- {
514
- name: 'list-item-count',
515
- matcher: (step) => step.text.includes('should have') && step.text.includes('count') &&
516
- !!step.selectorRef && step.text.includes('items') &&
517
- (step.elementType === 'list' || step.elementType === 'list-item' || step.elementType === 'listitem'),
518
- resolver: (step, context) => {
519
- let expectedCount = 1;
520
- const match = step.text.match(/count\s+(\d+)/);
521
- if (match) {
522
- expectedCount = parseInt(match[1]);
523
- }
524
- else if (step.dataRef) {
525
- try {
526
- const resolvedData = context.dataResolver.resolveData(step.dataRef, context.featureName);
527
- const parsed = parseInt(resolvedData);
528
- expectedCount = isNaN(parsed) ? 1 : parsed;
529
- }
530
- catch {
531
- expectedCount = `\${${step.dataRef}}`;
532
- }
533
- }
534
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
535
- return {
536
- templateName: 'list-item-count-assertion',
537
- data: { ...resolved, expectedCount },
538
- comment: `Assert ${step.selectorRef} list has ${expectedCount} items`,
539
- };
540
- },
541
- priority: 9, // Higher than should-have-count (8)
542
- },
543
- {
544
- name: 'should-have-count',
545
- matcher: (step) => step.text.includes('should have') && step.text.includes('count') && !!step.selectorRef,
546
- resolver: (step, context) => {
547
- let expectedCount = 1;
548
- // Try literal digit first: "count 10"
549
- const match = step.text.match(/count\s+(\d+)/);
550
- if (match) {
551
- expectedCount = parseInt(match[1]);
552
- }
553
- else if (step.dataRef) {
554
- // Resolve data reference: "count {{number_items}}"
555
- try {
556
- const resolvedData = context.dataResolver.resolveData(step.dataRef, context.featureName);
557
- const parsed = parseInt(resolvedData);
558
- expectedCount = isNaN(parsed) ? 1 : parsed;
559
- }
560
- catch {
561
- expectedCount = `\${${step.dataRef}}`;
562
- }
563
- }
564
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
565
- return {
566
- templateName: 'count-assertion',
567
- data: { ...resolved, expectedCount },
568
- comment: `Assert ${step.selectorRef} has count ${expectedCount}`,
569
- };
570
- },
571
- priority: 8,
572
- },
573
- {
574
- name: 'is-loading',
575
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis loading\b/.test(step.text) && !!step.selectorRef,
576
- resolver: (step, context) => {
577
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
578
- return {
579
- templateName: 'loading-assertion',
580
- data: { ...resolved, selectorRef: step.selectorRef },
581
- comment: `Assert ${step.selectorRef} is loading`,
582
- };
583
- },
584
- priority: 11,
585
- },
586
- {
587
- name: 'is-selected',
588
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bis selected\b/.test(step.text) && !!step.selectorRef,
589
- resolver: (step, context) => {
590
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
591
- return {
592
- templateName: 'selected-assertion',
593
- data: { ...resolved, selectorRef: step.selectorRef },
594
- comment: `Assert ${step.selectorRef} is selected`,
595
- };
596
- },
597
- priority: 11,
598
- },
599
- {
600
- name: 'is-sorted-ascending',
601
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bsorted ascending\b/.test(step.text) && !!step.selectorRef,
602
- resolver: (step, context) => {
603
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
604
- return {
605
- templateName: 'sorted-assertion',
606
- data: { ...resolved, selectorRef: step.selectorRef, sortDirection: 'ascending' },
607
- comment: `Assert ${step.selectorRef} is sorted ascending`,
608
- };
609
- },
610
- priority: 12,
611
- },
612
- {
613
- name: 'is-sorted-descending',
614
- matcher: (step) => /\b(see|sees)\s+\[/.test(step.text) && /\bsorted descending\b/.test(step.text) && !!step.selectorRef,
615
- resolver: (step, context) => {
616
- const resolved = context.selectorResolver.resolveSelector(step.selectorRef, undefined, step.elementType, step.nth);
617
- return {
618
- templateName: 'sorted-assertion',
619
- data: { ...resolved, selectorRef: step.selectorRef, sortDirection: 'descending' },
620
- comment: `Assert ${step.selectorRef} is sorted descending`,
621
- };
622
- },
623
- priority: 12,
624
- },
625
- ];
626
- //# sourceMappingURL=assertion-patterns.js.map