@sun-asterisk/sungen 1.0.20 → 1.0.21

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 (286) hide show
  1. package/dist/cli/commands/add.d.ts +3 -0
  2. package/dist/cli/commands/add.d.ts.map +1 -0
  3. package/dist/cli/commands/add.js +27 -0
  4. package/dist/cli/commands/add.js.map +1 -0
  5. package/dist/cli/commands/cache-clear.d.ts +3 -0
  6. package/dist/cli/commands/cache-clear.d.ts.map +1 -0
  7. package/dist/cli/commands/cache-clear.js +24 -0
  8. package/dist/cli/commands/cache-clear.js.map +1 -0
  9. package/dist/cli/commands/full.d.ts +3 -0
  10. package/dist/cli/commands/full.d.ts.map +1 -0
  11. package/dist/cli/commands/full.js +37 -0
  12. package/dist/cli/commands/full.js.map +1 -0
  13. package/dist/cli/commands/generate.d.ts +3 -0
  14. package/dist/cli/commands/generate.d.ts.map +1 -0
  15. package/dist/cli/commands/generate.js +53 -0
  16. package/dist/cli/commands/generate.js.map +1 -0
  17. package/dist/cli/commands/init.d.ts +3 -0
  18. package/dist/cli/commands/init.d.ts.map +1 -0
  19. package/dist/cli/commands/init.js +20 -0
  20. package/dist/cli/commands/init.js.map +1 -0
  21. package/dist/cli/commands/live-scan.d.ts +3 -0
  22. package/dist/cli/commands/live-scan.d.ts.map +1 -0
  23. package/dist/cli/commands/{live-scan-command.js → live-scan.js} +8 -15
  24. package/dist/cli/commands/live-scan.js.map +1 -0
  25. package/dist/cli/commands/makeauth.d.ts +3 -0
  26. package/dist/cli/commands/makeauth.d.ts.map +1 -0
  27. package/dist/cli/commands/makeauth.js +76 -0
  28. package/dist/cli/commands/makeauth.js.map +1 -0
  29. package/dist/cli/commands/map.d.ts +3 -0
  30. package/dist/cli/commands/map.d.ts.map +1 -0
  31. package/dist/cli/commands/map.js +93 -0
  32. package/dist/cli/commands/map.js.map +1 -0
  33. package/dist/cli/commands/validate.d.ts +3 -0
  34. package/dist/cli/commands/validate.d.ts.map +1 -0
  35. package/dist/cli/commands/validate.js +43 -0
  36. package/dist/cli/commands/validate.js.map +1 -0
  37. package/dist/cli/index.js +29 -442
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/cli/types.d.ts +9 -0
  40. package/dist/cli/types.d.ts.map +1 -0
  41. package/dist/cli/types.js +7 -0
  42. package/dist/cli/types.js.map +1 -0
  43. package/dist/cli/utils.d.ts +6 -0
  44. package/dist/cli/utils.d.ts.map +1 -0
  45. package/dist/cli/utils.js +101 -0
  46. package/dist/cli/utils.js.map +1 -0
  47. package/dist/core/live-scanner/matrix-reader.d.ts.map +1 -1
  48. package/dist/core/live-scanner/matrix-reader.js +2 -40
  49. package/dist/core/live-scanner/matrix-reader.js.map +1 -1
  50. package/dist/core/live-scanner/step-replayer.d.ts.map +1 -1
  51. package/dist/core/live-scanner/step-replayer.js +7 -0
  52. package/dist/core/live-scanner/step-replayer.js.map +1 -1
  53. package/dist/core/validator/selector-validator.d.ts.map +1 -1
  54. package/dist/core/validator/selector-validator.js +2 -1
  55. package/dist/core/validator/selector-validator.js.map +1 -1
  56. package/dist/generators/scaffold-generator/index.d.ts +2 -1
  57. package/dist/generators/scaffold-generator/index.d.ts.map +1 -1
  58. package/dist/generators/scaffold-generator/index.js +21 -1
  59. package/dist/generators/scaffold-generator/index.js.map +1 -1
  60. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  61. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  62. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  63. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  64. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  65. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  66. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  67. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  68. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  69. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  70. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  71. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  72. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  73. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  74. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  75. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  76. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  77. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  78. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  79. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  80. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  81. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  82. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  83. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  84. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  85. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  86. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  87. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  88. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  89. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  90. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  91. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  92. package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -58
  93. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  94. package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -2
  95. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
  96. package/dist/generators/test-generator/patterns/form-patterns.js +34 -47
  97. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
  98. package/dist/generators/test-generator/patterns/index.d.ts +3 -1
  99. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  100. package/dist/generators/test-generator/patterns/index.js +20 -3
  101. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  102. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -1
  103. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  104. package/dist/generators/test-generator/patterns/interaction-patterns.js +44 -85
  105. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  106. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +7 -0
  107. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +1 -0
  108. package/dist/generators/test-generator/patterns/legacy-patterns.js +98 -0
  109. package/dist/generators/test-generator/patterns/legacy-patterns.js.map +1 -0
  110. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -2
  111. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
  112. package/dist/generators/test-generator/patterns/navigation-patterns.js +14 -42
  113. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
  114. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -1
  115. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -1
  116. package/dist/generators/test-generator/patterns/setup-patterns.js +23 -35
  117. package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -1
  118. package/dist/generators/test-generator/patterns/types.d.ts +18 -3
  119. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  120. package/dist/generators/test-generator/step-mapper.d.ts +0 -15
  121. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  122. package/dist/generators/test-generator/step-mapper.js +4 -106
  123. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  124. package/dist/{executor/test-generator.d.ts → generators/test-generator/types.d.ts} +4 -25
  125. package/dist/generators/test-generator/types.d.ts.map +1 -0
  126. package/dist/generators/test-generator/types.js +106 -0
  127. package/dist/generators/test-generator/types.js.map +1 -0
  128. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  129. package/dist/generators/test-generator/utils/data-resolver.js +8 -17
  130. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  131. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  132. package/dist/generators/test-generator/utils/selector-resolver.js +10 -18
  133. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  134. package/dist/orchestrator/cache-manager.d.ts +1 -23
  135. package/dist/orchestrator/cache-manager.d.ts.map +1 -1
  136. package/dist/orchestrator/cache-manager.js +1 -87
  137. package/dist/orchestrator/cache-manager.js.map +1 -1
  138. package/dist/orchestrator/pipeline.d.ts +11 -28
  139. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  140. package/dist/orchestrator/pipeline.js +52 -371
  141. package/dist/orchestrator/pipeline.js.map +1 -1
  142. package/dist/orchestrator/reporter.d.ts +1 -1
  143. package/dist/orchestrator/reporter.d.ts.map +1 -1
  144. package/dist/orchestrator/screen-manager.js +1 -1
  145. package/dist/orchestrator/screen-manager.js.map +1 -1
  146. package/dist/utils/feature-finder.d.ts +9 -0
  147. package/dist/utils/feature-finder.d.ts.map +1 -0
  148. package/dist/utils/feature-finder.js +67 -0
  149. package/dist/utils/feature-finder.js.map +1 -0
  150. package/dist/utils/screen-paths.d.ts +10 -0
  151. package/dist/utils/screen-paths.d.ts.map +1 -0
  152. package/dist/utils/screen-paths.js +73 -0
  153. package/dist/utils/screen-paths.js.map +1 -0
  154. package/dist/utils/selector-loader.d.ts +6 -0
  155. package/dist/utils/selector-loader.d.ts.map +1 -0
  156. package/dist/utils/selector-loader.js +20 -0
  157. package/dist/utils/selector-loader.js.map +1 -0
  158. package/dist/utils/selector-types.d.ts +7 -0
  159. package/dist/utils/selector-types.d.ts.map +1 -0
  160. package/dist/utils/selector-types.js +19 -0
  161. package/dist/utils/selector-types.js.map +1 -0
  162. package/dist/utils/test-data-loader.d.ts +6 -0
  163. package/dist/utils/test-data-loader.d.ts.map +1 -0
  164. package/dist/utils/test-data-loader.js +20 -0
  165. package/dist/utils/test-data-loader.js.map +1 -0
  166. package/dist/utils/yaml-io.d.ts +14 -0
  167. package/dist/utils/yaml-io.d.ts.map +1 -0
  168. package/dist/utils/yaml-io.js +72 -0
  169. package/dist/utils/yaml-io.js.map +1 -0
  170. package/package.json +1 -1
  171. package/src/cli/commands/add.ts +25 -0
  172. package/src/cli/commands/cache-clear.ts +22 -0
  173. package/src/cli/commands/full.ts +35 -0
  174. package/src/cli/commands/generate.ts +55 -0
  175. package/src/cli/commands/init.ts +17 -0
  176. package/src/cli/commands/{live-scan-command.ts → live-scan.ts} +8 -17
  177. package/src/cli/commands/makeauth.ts +77 -0
  178. package/src/cli/commands/map.ts +97 -0
  179. package/src/cli/commands/validate.ts +43 -0
  180. package/src/cli/index.ts +32 -473
  181. package/src/cli/types.ts +9 -0
  182. package/src/cli/utils.ts +106 -0
  183. package/src/core/live-scanner/matrix-reader.ts +2 -8
  184. package/src/core/live-scanner/step-replayer.ts +7 -0
  185. package/src/core/validator/selector-validator.ts +3 -2
  186. package/src/generators/scaffold-generator/index.ts +23 -2
  187. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  188. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  189. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  190. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  191. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  192. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  193. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  194. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  195. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  196. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  197. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  198. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  199. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  200. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  201. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  202. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  203. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  204. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  205. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  206. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  207. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  208. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  209. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  210. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  211. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  212. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  213. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  214. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  215. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  216. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  217. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  218. package/src/generators/test-generator/patterns/assertion-patterns.ts +102 -62
  219. package/src/generators/test-generator/patterns/form-patterns.ts +38 -60
  220. package/src/generators/test-generator/patterns/index.ts +22 -4
  221. package/src/generators/test-generator/patterns/interaction-patterns.ts +47 -107
  222. package/src/generators/test-generator/patterns/legacy-patterns.ts +104 -0
  223. package/src/generators/test-generator/patterns/navigation-patterns.ts +27 -69
  224. package/src/generators/test-generator/patterns/setup-patterns.ts +23 -41
  225. package/src/generators/test-generator/patterns/types.ts +26 -9
  226. package/src/generators/test-generator/step-mapper.ts +4 -124
  227. package/src/generators/test-generator/types.ts +131 -0
  228. package/src/generators/test-generator/utils/data-resolver.ts +8 -13
  229. package/src/generators/test-generator/utils/selector-resolver.ts +15 -17
  230. package/src/orchestrator/cache-manager.ts +1 -107
  231. package/src/orchestrator/pipeline.ts +58 -433
  232. package/src/orchestrator/reporter.ts +1 -1
  233. package/src/orchestrator/screen-manager.ts +1 -1
  234. package/src/utils/feature-finder.ts +33 -0
  235. package/src/utils/screen-paths.ts +37 -0
  236. package/src/utils/selector-loader.ts +23 -0
  237. package/src/utils/selector-types.ts +17 -0
  238. package/src/utils/test-data-loader.ts +23 -0
  239. package/src/utils/yaml-io.ts +33 -0
  240. package/dist/cli/commands/auto-tag-command.d.ts +0 -8
  241. package/dist/cli/commands/auto-tag-command.d.ts.map +0 -1
  242. package/dist/cli/commands/auto-tag-command.js +0 -104
  243. package/dist/cli/commands/auto-tag-command.js.map +0 -1
  244. package/dist/cli/commands/live-scan-command.d.ts +0 -9
  245. package/dist/cli/commands/live-scan-command.d.ts.map +0 -1
  246. package/dist/cli/commands/live-scan-command.js.map +0 -1
  247. package/dist/executor/playwright/playwright-generator.d.ts +0 -33
  248. package/dist/executor/playwright/playwright-generator.d.ts.map +0 -1
  249. package/dist/executor/playwright/playwright-generator.js +0 -136
  250. package/dist/executor/playwright/playwright-generator.js.map +0 -1
  251. package/dist/executor/test-generator.d.ts.map +0 -1
  252. package/dist/executor/test-generator.js +0 -30
  253. package/dist/executor/test-generator.js.map +0 -1
  254. package/dist/generators/cli.d.ts +0 -7
  255. package/dist/generators/cli.d.ts.map +0 -1
  256. package/dist/generators/cli.js +0 -570
  257. package/dist/generators/cli.js.map +0 -1
  258. package/dist/input/cli-adapter.d.ts +0 -75
  259. package/dist/input/cli-adapter.d.ts.map +0 -1
  260. package/dist/input/cli-adapter.js +0 -218
  261. package/dist/input/cli-adapter.js.map +0 -1
  262. package/dist/input/config-adapter.d.ts +0 -25
  263. package/dist/input/config-adapter.d.ts.map +0 -1
  264. package/dist/input/config-adapter.js +0 -70
  265. package/dist/input/config-adapter.js.map +0 -1
  266. package/dist/input/input-adapter.d.ts +0 -28
  267. package/dist/input/input-adapter.d.ts.map +0 -1
  268. package/dist/input/input-adapter.js +0 -17
  269. package/dist/input/input-adapter.js.map +0 -1
  270. package/dist/input/vscode-adapter.d.ts +0 -62
  271. package/dist/input/vscode-adapter.d.ts.map +0 -1
  272. package/dist/input/vscode-adapter.js +0 -64
  273. package/dist/input/vscode-adapter.js.map +0 -1
  274. package/dist/tools/auto-tagger.d.ts +0 -107
  275. package/dist/tools/auto-tagger.d.ts.map +0 -1
  276. package/dist/tools/auto-tagger.js +0 -502
  277. package/dist/tools/auto-tagger.js.map +0 -1
  278. package/src/cli/commands/auto-tag-command.ts +0 -80
  279. package/src/executor/playwright/playwright-generator.ts +0 -125
  280. package/src/executor/test-generator.ts +0 -90
  281. package/src/generators/cli.ts +0 -640
  282. package/src/input/cli-adapter.ts +0 -233
  283. package/src/input/config-adapter.ts +0 -71
  284. package/src/input/input-adapter.ts +0 -32
  285. package/src/input/vscode-adapter.ts +0 -90
  286. package/src/tools/auto-tagger.ts +0 -572
@@ -1,16 +1,12 @@
1
1
  /**
2
2
  * Pipeline Orchestrator
3
- * Coordinates all phases of test generation: UI Scan → Selector Mapping → Code Generation
3
+ * Coordinates test generation: Live-Scan → Scaffold → Code Generation
4
4
  */
5
5
 
6
6
  import * as path from 'path';
7
7
  import * as fs from 'fs';
8
- import yaml from 'yaml';
9
8
  import { RuntimeConfig } from '../config/config-schema';
10
- import { ScannerFactory, UIModel } from '../core/ui-scanner/scanner-interface';
11
- import { SelectorBaseGenerator, SelectorBase } from '../core/selector-base/base-generator';
12
- import { AIProviderFactory } from '../external/ai-provider';
13
- import { TestGeneratorFactory, GeneratedTest } from '../executor/test-generator';
9
+ import { TestGeneratorFactory, GeneratedTest } from '../generators/test-generator/types';
14
10
  import { CacheManager } from './cache-manager';
15
11
  import { Reporter } from './reporter';
16
12
 
@@ -25,334 +21,6 @@ export class Pipeline {
25
21
  this.reporter = new Reporter(config);
26
22
  }
27
23
 
28
- /**
29
- * Run UI discovery phase
30
- * Scans React components and generates UI model
31
- */
32
- async runDiscovery(screenName: string): Promise<UIModel> {
33
- const strictMode = this.config.scanner.strictMode || false;
34
- const mode = strictMode ? 'strict' : 'standard';
35
-
36
- // Debug logging
37
- if (this.config.verbose) {
38
- console.log(`[DEBUG] strictMode value: ${this.config.scanner.strictMode}`);
39
- console.log(`[DEBUG] scanner config:`, JSON.stringify(this.config.scanner, null, 2));
40
- }
41
-
42
- console.log(`\n🔍 Discovering UI elements for screen: ${screenName} (${mode} mode)\n`);
43
-
44
- // Check cache
45
- if (!this.config.force && this.config.cache.enabled) {
46
- const cached = await this.cacheManager.getUIModel(screenName);
47
- if (cached) {
48
- console.log(`✓ Loaded from cache (${cached.elements.length} elements)\n`);
49
- return cached;
50
- }
51
- }
52
-
53
- let uiModel: UIModel;
54
-
55
- // Use StrictScanner if strict mode enabled (v3.1)
56
- if (strictMode) {
57
- const { StrictScanner } = require('../core/ui-scanner/strict-scanner');
58
-
59
- const strictConfig = {
60
- sourceRoot: this.config.paths.sourceRoot,
61
- projectRoot: process.cwd(),
62
- strictMode: true,
63
- filterRules: this.config.scanner.filterRules || {
64
- allowedTags: ['input', 'button', 'a', 'select', 'textarea'],
65
- requireAttributes: ['data-testid', 'role'],
66
- allowGenericWithId: true,
67
- },
68
- verbose: this.config.verbose || false,
69
- };
70
-
71
- const strictScanner = new StrictScanner(strictConfig);
72
- const strictResult = await strictScanner.scan(screenName);
73
-
74
- // Convert StrictScanResult to UIModel format
75
- uiModel = {
76
- screen: strictResult.screen,
77
- timestamp: strictResult.timestamp,
78
- framework: strictResult.framework,
79
- sourceFiles: strictResult.sourceFiles,
80
- elements: strictResult.elements.map(el => ({
81
- id: el.logicalName,
82
- type: el.tag as any,
83
- selector: el.primaryLocator,
84
- label: el.label,
85
- placeholder: el.placeholder,
86
- role: el.role,
87
- testId: el.props['data-testid'],
88
- context: {
89
- component: path.basename(el.sourceFile),
90
- },
91
- })),
92
- stats: {
93
- totalComponents: 1,
94
- totalElements: strictResult.stats.totalIncluded,
95
- maxDepth: 0,
96
- scanDuration: strictResult.stats.scanDuration,
97
- filesScanned: strictResult.sourceFiles.length,
98
- },
99
- };
100
-
101
- console.log(` Filtered: ${strictResult.stats.totalFiltered} elements (${strictResult.stats.filterRate.toFixed(1)}%)`);
102
- console.log(` Direct ID: ${strictResult.stats.directIdMatches} elements`);
103
- } else {
104
- // Use standard scanner (old approach)
105
- const scanner = ScannerFactory.create(this.config.scanner.framework, this.config);
106
- uiModel = await scanner.scan(screenName, this.config);
107
- }
108
-
109
- // Save UI model
110
- await this.saveUIModel(uiModel);
111
-
112
- // Cache UI model
113
- if (this.config.cache.enabled) {
114
- await this.cacheManager.saveUIModel(screenName, uiModel);
115
- }
116
-
117
- console.log(`✓ Discovered ${uiModel.elements.length} elements in ${uiModel.stats.scanDuration}ms\n`);
118
-
119
- return uiModel;
120
- }
121
-
122
- /**
123
- * Run mapping for single screen or all screens
124
- */
125
- async runMapping(screenName?: string): Promise<void> {
126
- if (screenName) {
127
- // Map specific screen
128
- await this.runSelectorMapping(screenName);
129
- } else {
130
- // Map all screens discovered from Gherkin
131
- const screens = await this.discoverScreensFromGherkin();
132
-
133
- if (screens.length === 0) {
134
- console.warn('⚠️ No screens found in Gherkin features');
135
- return;
136
- }
137
-
138
- console.log(`📋 Found ${screens.length} screen(s): ${screens.join(', ')}\n`);
139
-
140
- for (const screen of screens) {
141
- await this.runSelectorMapping(screen);
142
- }
143
- }
144
- }
145
-
146
- /**
147
- * Run selector mapping phase
148
- * Generates selector base and maps with AI or Hybrid Mapper
149
- */
150
- async runSelectorMapping(screenName: string): Promise<SelectorBase> {
151
- const mode = this.config.selectorMapping.mode || 'hybrid';
152
- console.log(`\n🎯 Mapping selectors for screen: ${screenName} (mode: ${mode})\n`);
153
-
154
- // Check cache
155
- if (!this.config.force && this.config.cache.enabled) {
156
- const cached = await this.cacheManager.getSelectors(screenName);
157
- if (cached) {
158
- console.log(`✓ Loaded from cache (${Object.keys(cached.elements).length} selectors)\n`);
159
- return cached;
160
- }
161
- }
162
-
163
- // Generate selector base from Gherkin
164
- const baseGenerator = new SelectorBaseGenerator(this.config);
165
- const selectorBase = await baseGenerator.generate(screenName);
166
-
167
- console.log(` Generated selector base with ${selectorBase.metadata.totalElements} elements`);
168
-
169
- // Load UI model (needed for mapping)
170
- const uiModel = await this.loadUIModel(screenName);
171
- if (!uiModel) {
172
- throw new Error(`UI model not found for screen: ${screenName}. Run discovery first.`);
173
- }
174
-
175
- // Map selectors based on mode/strategy
176
- let mappedSelectors: SelectorBase;
177
-
178
- // v3.1: Use PriorityMapper if strategy is priority-waterfall
179
- const strategy = this.config.selectorMapping.strategy;
180
- if (strategy === 'priority-waterfall') {
181
- const { PriorityMapper } = require('../core/selector-mapper/priority-mapper');
182
-
183
- const mapperConfig = {
184
- strategy: 'priority-waterfall' as const,
185
- priorities: this.config.selectorMapping.priorities || ['direct-id', 'accessibility', 'heuristic-ai'],
186
- confidenceThreshold: this.config.selectorMapping.confidenceThreshold || 0.5,
187
- aiProvider: this.config.selectorMapping.aiProvider,
188
- model: this.config.selectorMapping.model,
189
- };
190
-
191
- const priorityMapper = new PriorityMapper(mapperConfig);
192
-
193
- // Extract element IDs from selector base
194
- const elementIds = Object.keys(selectorBase.elements);
195
-
196
- // Convert UI model to StrictScanResult format (compatible)
197
- const strictUIModel = {
198
- screen: uiModel.screen,
199
- timestamp: uiModel.timestamp,
200
- framework: uiModel.framework,
201
- sourceFiles: uiModel.sourceFiles,
202
- elements: uiModel.elements.map(el => {
203
- // Check if selector contains data-testid
204
- const hasTestId = el.selector.includes('data-testid');
205
-
206
- return {
207
- logicalName: el.id,
208
- primaryLocator: el.selector,
209
- fallbackStrategy: el.selector,
210
- tag: el.type,
211
- elementType: el.type,
212
- discoveryMethod: hasTestId ? 'direct-id' : 'heuristic' as const,
213
- confidence: hasTestId ? 0.95 : 0.5,
214
- sourceFile: uiModel.sourceFiles[0] || '',
215
- label: el.label,
216
- placeholder: el.placeholder,
217
- ariaLabel: undefined,
218
- role: el.role,
219
- text: undefined,
220
- props: {},
221
- };
222
- }),
223
- stats: {
224
- totalScanned: uiModel.stats.totalElements,
225
- totalFiltered: 0,
226
- totalIncluded: uiModel.stats.totalElements,
227
- filterRate: 0,
228
- directIdMatches: uiModel.elements.filter(el => el.selector.includes('data-testid')).length,
229
- accessibilityMatches: 0,
230
- heuristicMatches: uiModel.elements.filter(el => !el.selector.includes('data-testid')).length,
231
- scanDuration: uiModel.stats.scanDuration,
232
- },
233
- };
234
-
235
- // Map elements using priority waterfall
236
- const mappingRequests = elementIds.map(id => ({
237
- elementId: `[${screenName}.${id}]`,
238
- screenName,
239
- uiModel: strictUIModel,
240
- }));
241
-
242
- const results = await priorityMapper.mapElements(mappingRequests);
243
-
244
- // Convert results back to SelectorBase format
245
- mappedSelectors = { ...selectorBase };
246
- results.forEach(result => {
247
- // result.elementId is already just the element name (e.g., "email-input")
248
- const elementId = result.elementId;
249
-
250
- if (this.config.verbose) {
251
- console.log(`[DEBUG] Mapping result: ${result.elementId} → ${result.selector} (confidence: ${result.confidence})`);
252
- console.log(`[DEBUG] Extracted elementId: ${elementId}`);
253
- }
254
-
255
- if (elementId && result.confidence > 0 && selectorBase.elements[elementId]) {
256
- mappedSelectors.elements[elementId] = {
257
- ...selectorBase.elements[elementId],
258
- selector: result.selector,
259
- };
260
-
261
- if (this.config.verbose) {
262
- console.log(`[DEBUG] Updated selector for ${elementId}: ${mappedSelectors.elements[elementId].selector}`);
263
- }
264
- }
265
- });
266
-
267
- // Show statistics
268
- const stats = priorityMapper.getStats();
269
- console.log(`\n📊 Priority Mapping Statistics:`);
270
- console.log(` Total elements: ${stats.totalMappings}`);
271
- console.log(` Successful: ${stats.successfulMappings} (${((stats.successfulMappings / stats.totalMappings) * 100).toFixed(1)}%)`);
272
- console.log(` Direct ID: ${stats.directIdMatches} (${((stats.directIdMatches / stats.totalMappings) * 100).toFixed(1)}%)`);
273
- console.log(` Accessibility: ${stats.accessibilityMatches}`);
274
- console.log(` Heuristic: ${stats.heuristicMatches}`);
275
- console.log(` AI: ${stats.aiMatches}`);
276
- console.log(` Avg time: ${stats.averageMappingTime.toFixed(2)}ms`);
277
- console.log(` Cost: $${stats.estimatedCost.toFixed(4)}\n`);
278
- } else if (mode === 'hybrid') {
279
- // Use Hybrid Mapper (heuristics + AI fallback)
280
- const { HybridMapper } = require('../generators/selector-mapper/hybrid-mapper');
281
- const hybridMapper = new HybridMapper({
282
- provider: this.config.selectorMapping.aiProvider,
283
- model: this.config.selectorMapping.model,
284
- apiKey: process.env[this.config.apis.anthropic.apiKeyEnv],
285
- heuristicFirst: this.config.selectorMapping.heuristicFirst,
286
- minHeuristicConfidence: this.config.selectorMapping.minHeuristicConfidence,
287
- verbose: this.config.verbose
288
- });
289
-
290
- // Extract element IDs from selector base
291
- const elementIds = Object.keys(selectorBase.elements).map(id => `[${screenName}.${id}]`);
292
-
293
- // Map using hybrid approach
294
- const selectorDSL = await hybridMapper.mapSelectors(uiModel, elementIds);
295
-
296
- // Convert SelectorDSL back to SelectorBase format
297
- // selectorDSL is a flat object { elementId: SelectorEntry }
298
- mappedSelectors = {
299
- ...selectorBase,
300
- elements: selectorDSL
301
- };
302
-
303
- // Show statistics if verbose
304
- if (this.config.verbose) {
305
- const stats = hybridMapper.getStats();
306
- console.log(`\n📊 Mapping Statistics:`);
307
- console.log(` Total elements: ${stats.total}`);
308
- console.log(` Heuristic matches: ${stats.heuristicMatches} (${stats.heuristicSuccessRate.toFixed(1)}%)`);
309
- console.log(` AI fallback: ${stats.aiMatches} (${(100 - stats.heuristicSuccessRate).toFixed(1)}%)`);
310
- console.log(` Estimated cost: $${stats.estimatedCost.toFixed(4)}`);
311
- console.log(` Estimated time: ${stats.estimatedTime}ms`);
312
- console.log(` Savings vs AI-only: ~${(90 * stats.heuristicSuccessRate / 100).toFixed(0)}%\n`);
313
- }
314
- } else if (mode === 'ai-only') {
315
- // Use AI mapper only (legacy behavior)
316
- const aiProvider = AIProviderFactory.create(this.config.selectorMapping.aiProvider, this.config);
317
- mappedSelectors = await aiProvider.mapSelectors(uiModel, selectorBase, this.config);
318
- } else if (mode === 'heuristic-only') {
319
- // Use heuristics only (no AI fallback)
320
- const { HeuristicMatcher } = require('../generators/selector-mapper/hybrid-mapper');
321
-
322
- mappedSelectors = { ...selectorBase };
323
-
324
- for (const [elementId, element] of Object.entries(selectorBase.elements)) {
325
- const match = HeuristicMatcher.match(elementId, uiModel.elements);
326
-
327
- if (match.confidence > 0) {
328
- mappedSelectors.elements[elementId] = {
329
- ...element,
330
- selector: match.selector
331
- };
332
- } else {
333
- console.warn(` ⚠️ No heuristic match for: ${elementId}`);
334
- }
335
- }
336
- } else {
337
- throw new Error(`Invalid selector mapping mode: ${mode}`);
338
- }
339
-
340
- // Apply overrides
341
- const finalSelectors = await this.applyOverrides(screenName, mappedSelectors);
342
-
343
- // Save selectors
344
- await baseGenerator.save(finalSelectors);
345
-
346
- // Cache selectors
347
- if (this.config.cache.enabled) {
348
- await this.cacheManager.saveSelectors(screenName, finalSelectors);
349
- }
350
-
351
- console.log(`✓ Mapped ${Object.keys(finalSelectors.elements).length} selectors\n`);
352
-
353
- return finalSelectors;
354
- }
355
-
356
24
  /**
357
25
  * Run test generation phase
358
26
  * Generates Playwright test scripts from Gherkin
@@ -362,10 +30,10 @@ export class Pipeline {
362
30
  console.log(`\n${header}\n`);
363
31
 
364
32
  // Find all feature files from both old and new structure
365
- const featureFiles = screenName
33
+ const featureFiles = screenName
366
34
  ? this.findFeatureFilesForScreen(screenName)
367
35
  : this.findAllFeatureFiles();
368
-
36
+
369
37
  if (screenName && featureFiles.length === 0) {
370
38
  throw new Error(
371
39
  `No feature files found for screen: ${screenName}\n` +
@@ -384,7 +52,7 @@ export class Pipeline {
384
52
  if (screenName) {
385
53
  const validation = this.validateSelectorFiles(screenName, features);
386
54
  const missing = validation.filter(v => !v.selectorExists);
387
-
55
+
388
56
  if (missing.length > 0) {
389
57
  const missingList = missing.map(v => ` ✗ ${v.featureName}.feature → selector file not found`).join('\n');
390
58
  throw new Error(
@@ -412,7 +80,7 @@ export class Pipeline {
412
80
  const fileName = path.basename(result.outputPath);
413
81
  const relativePath = path.relative(process.cwd(), result.outputPath);
414
82
  const stepInfo = result.stats?.totalSteps ? ` (${result.stats.totalSteps} steps)` : '';
415
-
83
+
416
84
  console.log(`✓ Generated ${fileName}`);
417
85
  console.log(` → ${relativePath}${stepInfo}\n`);
418
86
  } catch (error) {
@@ -455,11 +123,11 @@ export class Pipeline {
455
123
  selectorExists: boolean;
456
124
  selectorPath: string | null;
457
125
  }> = [];
458
-
126
+
459
127
  for (const feature of features) {
460
128
  const featureName = this.extractFeatureName(feature);
461
129
  const selectorPath = this.findSelectorFile(screenName, featureName);
462
-
130
+
463
131
  results.push({
464
132
  featureName,
465
133
  sourceFile: feature.sourceFile,
@@ -467,7 +135,7 @@ export class Pipeline {
467
135
  selectorPath,
468
136
  });
469
137
  }
470
-
138
+
471
139
  return results;
472
140
  }
473
141
 
@@ -484,7 +152,6 @@ export class Pipeline {
484
152
 
485
153
  /**
486
154
  * Find selector file path for a feature
487
- * Searches both old and new directory structures
488
155
  */
489
156
  private findSelectorFile(screenName: string, featureName: string): string | null {
490
157
  const possiblePaths: string[] = [];
@@ -510,7 +177,6 @@ export class Pipeline {
510
177
  );
511
178
  possiblePaths.push(oldStructurePath);
512
179
 
513
- // Find first existing file
514
180
  for (const p of possiblePaths) {
515
181
  if (fs.existsSync(p)) {
516
182
  return p;
@@ -521,10 +187,12 @@ export class Pipeline {
521
187
  }
522
188
 
523
189
  /**
524
- * Run full pipeline
525
- * Discovery → Selector Mapping → Test Generation
190
+ * Run full pipeline: Live-Scan → Scaffold → Test Generation
526
191
  */
527
- async runFull(screens?: string[]): Promise<void> {
192
+ async runFull(
193
+ screens?: string[],
194
+ options?: { headed?: boolean; authDir?: string; skipLiveScan?: boolean; force?: boolean }
195
+ ): Promise<void> {
528
196
  console.log('\n🚀 Running full pipeline\n');
529
197
 
530
198
  // Discover screens if not specified
@@ -533,20 +201,43 @@ export class Pipeline {
533
201
  console.log(` Found ${screens.length} screen(s) in Gherkin: ${screens.join(', ')}\n`);
534
202
  }
535
203
 
536
- // Phase 1: UI Discovery
537
- console.log('📍 Phase 1: UI Discovery\n');
538
- for (const screen of screens) {
539
- await this.runDiscovery(screen);
540
- }
204
+ const screensDir = 'qa/screens';
541
205
 
542
- // Phase 2: Selector Mapping
543
- console.log('📍 Phase 2: Selector Mapping\n');
544
206
  for (const screen of screens) {
545
- await this.runSelectorMapping(screen);
207
+ // Phase 1: Live-scan
208
+ if (!options?.skipLiveScan) {
209
+ console.log(`📍 Phase 1: Live-Scan — ${screen}\n`);
210
+ const { LiveScanner } = require('../core/live-scanner');
211
+ const scanner = new LiveScanner({
212
+ screenName: screen,
213
+ screensDir,
214
+ headed: options?.headed,
215
+ authDir: options?.authDir || 'specs/.auth',
216
+ force: options?.force,
217
+ });
218
+ await scanner.scan();
219
+ console.log('');
220
+ }
221
+
222
+ // Phase 2: Scaffold (map)
223
+ console.log(`📍 Phase 2: Map — ${screen}\n`);
224
+ const { ScaffoldGenerator } = require('../generators/scaffold-generator');
225
+ const generator = new ScaffoldGenerator();
226
+ const results = generator.processScreen(screen, screensDir, options?.force || false);
227
+
228
+ for (const result of results) {
229
+ console.log(`✓ Mapped ${result.featureFile}.feature`);
230
+ if (result.selectorsSkipped) {
231
+ console.log(` ⊘ ${path.basename(result.selectorsPath)} (skipped - already exists)`);
232
+ } else {
233
+ console.log(` → ${path.basename(result.selectorsPath)} (${result.elementCount} elements)`);
234
+ }
235
+ console.log('');
236
+ }
546
237
  }
547
238
 
548
239
  // Phase 3: Test Generation
549
- console.log('📍 Phase 3: Test Generation\n');
240
+ console.log('📍 Phase 3: Generate Tests\n');
550
241
  await this.runTestGeneration();
551
242
 
552
243
  console.log('✅ Full pipeline completed!\n');
@@ -564,65 +255,6 @@ export class Pipeline {
564
255
  // Helper Methods
565
256
  // ============================================================================
566
257
 
567
- private async saveUIModel(uiModel: UIModel): Promise<void> {
568
- const outputDir = path.join(this.config.paths.uiModelsDir, 'screens');
569
- if (!fs.existsSync(outputDir)) {
570
- fs.mkdirSync(outputDir, { recursive: true });
571
- }
572
-
573
- const outputPath = path.join(outputDir, `${uiModel.screen}.json`);
574
- fs.writeFileSync(outputPath, JSON.stringify(uiModel, null, 2), 'utf-8');
575
- }
576
-
577
- private async loadUIModel(screenName: string): Promise<UIModel | null> {
578
- const filePath = path.join(this.config.paths.uiModelsDir, 'screens', `${screenName}.json`);
579
-
580
- if (!fs.existsSync(filePath)) {
581
- return null;
582
- }
583
-
584
- try {
585
- const content = fs.readFileSync(filePath, 'utf-8');
586
- return JSON.parse(content);
587
- } catch {
588
- return null;
589
- }
590
- }
591
-
592
- private async applyOverrides(screenName: string, selectors: SelectorBase): Promise<SelectorBase> {
593
- const overridePath = path.join(
594
- this.config.paths.selectorsDir,
595
- 'screens',
596
- `${screenName}.override.yaml`
597
- );
598
-
599
- if (!fs.existsSync(overridePath)) {
600
- return selectors;
601
- }
602
-
603
- try {
604
- const content = fs.readFileSync(overridePath, 'utf-8');
605
- const overrides = yaml.parse(content);
606
-
607
- // Merge overrides (override values replace AI values)
608
- if (overrides.elements) {
609
- for (const [elementId, overrideValue] of Object.entries(overrides.elements)) {
610
- if (selectors.elements[elementId]) {
611
- Object.assign(selectors.elements[elementId], overrideValue);
612
- }
613
- }
614
- }
615
-
616
- if (this.config.verbose) {
617
- console.log(` Applied overrides from ${path.basename(overridePath)}`);
618
- }
619
- } catch (error) {
620
- console.warn(` Warning: Failed to apply overrides: ${error}`);
621
- }
622
-
623
- return selectors;
624
- }
625
-
626
258
  private findFeatureFiles(dir: string): string[] {
627
259
  const files: string[] = [];
628
260
 
@@ -677,8 +309,6 @@ export class Pipeline {
677
309
 
678
310
  /**
679
311
  * Find all feature files from both old and new folder structures
680
- * Old: qa/features/*.feature
681
- * New: qa/screens/*/features/*.feature
682
312
  */
683
313
  private findAllFeatureFiles(): string[] {
684
314
  const allFiles: string[] = [];
@@ -704,26 +334,21 @@ export class Pipeline {
704
334
  }
705
335
 
706
336
  /**
707
- * Discover all unique screens referenced in Gherkin features
337
+ * Discover all unique screens from qa/screens/ directory
708
338
  */
709
339
  private async discoverScreensFromGherkin(): Promise<string[]> {
710
- const featureFiles = this.findAllFeatureFiles();
711
- const screens = new Set<string>();
712
-
713
- // Regex to match [screen.element] pattern
714
- const selectorPattern = /\[([a-z0-9-]+)\.([a-z0-9-]+)\]/gi;
715
-
716
- for (const featureFile of featureFiles) {
717
- const content = fs.readFileSync(featureFile, 'utf-8');
718
-
719
- // Extract all [screen.element] references
720
- let match;
721
- while ((match = selectorPattern.exec(content)) !== null) {
722
- const screenName = match[1];
723
- screens.add(screenName);
724
- }
340
+ const screensDir = path.join(process.cwd(), 'qa', 'screens');
341
+ if (!fs.existsSync(screensDir)) {
342
+ return [];
725
343
  }
726
344
 
727
- return Array.from(screens).sort();
345
+ return fs.readdirSync(screensDir, { withFileTypes: true })
346
+ .filter(entry => entry.isDirectory())
347
+ .filter(entry => {
348
+ const featuresDir = path.join(screensDir, entry.name, 'features');
349
+ return fs.existsSync(featuresDir);
350
+ })
351
+ .map(entry => entry.name)
352
+ .sort();
728
353
  }
729
354
  }
@@ -6,7 +6,7 @@
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
8
  import { RuntimeConfig } from '../config/config-schema';
9
- import { GeneratedTest } from '../executor/test-generator';
9
+ import { GeneratedTest } from '../generators/test-generator/types';
10
10
 
11
11
  export class Reporter {
12
12
  private config: RuntimeConfig;
@@ -182,7 +182,7 @@ export class ScreenManager {
182
182
 
183
183
  @high
184
184
  Scenario: Sample scenario for ${options.name}
185
- Given User open [${options.name}] page
185
+ Given User is on [${options.name}] page
186
186
  When User click [element] button
187
187
  Then User see [result] text with {{success}}
188
188
  `;
@@ -0,0 +1,33 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { getFeaturesDir } from './screen-paths';
4
+
5
+ /**
6
+ * Find all .feature files for a specific screen.
7
+ */
8
+ export function findFeatureFiles(screensRoot: string, screenName: string): string[] {
9
+ const featuresDir = getFeaturesDir(screensRoot, screenName);
10
+ if (!fs.existsSync(featuresDir)) {
11
+ return [];
12
+ }
13
+ return fs.readdirSync(featuresDir)
14
+ .filter(f => f.endsWith('.feature'))
15
+ .map(f => path.join(featuresDir, f));
16
+ }
17
+
18
+ /**
19
+ * Find all .feature files across all screens.
20
+ */
21
+ export function findAllFeatureFiles(screensRoot: string): string[] {
22
+ if (!fs.existsSync(screensRoot)) {
23
+ return [];
24
+ }
25
+ const files: string[] = [];
26
+ const screens = fs.readdirSync(screensRoot).filter(d =>
27
+ fs.statSync(path.join(screensRoot, d)).isDirectory()
28
+ );
29
+ for (const screen of screens) {
30
+ files.push(...findFeatureFiles(screensRoot, screen));
31
+ }
32
+ return files;
33
+ }
@@ -0,0 +1,37 @@
1
+ import * as path from 'path';
2
+
3
+ export function getScreenDir(screensRoot: string, screenName: string): string {
4
+ return path.join(screensRoot, screenName);
5
+ }
6
+
7
+ export function getFeaturesDir(screensRoot: string, screenName: string): string {
8
+ return path.join(screensRoot, screenName, 'features');
9
+ }
10
+
11
+ export function getSelectorsDir(screensRoot: string, screenName: string): string {
12
+ return path.join(screensRoot, screenName, 'selectors');
13
+ }
14
+
15
+ export function getTestDataDir(screensRoot: string, screenName: string): string {
16
+ return path.join(screensRoot, screenName, 'test-data');
17
+ }
18
+
19
+ export function getSelectorBasePath(screensRoot: string, screenName: string, featureName: string): string {
20
+ return path.join(screensRoot, screenName, 'selectors', `${featureName}.yaml`);
21
+ }
22
+
23
+ export function getSelectorOverridePath(screensRoot: string, screenName: string, featureName: string): string {
24
+ return path.join(screensRoot, screenName, 'selectors', `${featureName}.override.yaml`);
25
+ }
26
+
27
+ export function getTestDataBasePath(screensRoot: string, screenName: string, featureName: string): string {
28
+ return path.join(screensRoot, screenName, 'test-data', `${featureName}.yaml`);
29
+ }
30
+
31
+ export function getTestDataOverridePath(screensRoot: string, screenName: string, featureName: string): string {
32
+ return path.join(screensRoot, screenName, 'test-data', `${featureName}.override.yaml`);
33
+ }
34
+
35
+ export function getLiveScanPath(screensRoot: string, screenName: string, featureName: string): string {
36
+ return path.join(screensRoot, screenName, 'selectors', `${featureName}.live-scan.yaml`);
37
+ }