@sun-asterisk/sungen 1.0.19 → 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 (295) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/commands/add.d.ts +3 -0
  3. package/dist/cli/commands/add.d.ts.map +1 -0
  4. package/dist/cli/commands/add.js +27 -0
  5. package/dist/cli/commands/add.js.map +1 -0
  6. package/dist/cli/commands/cache-clear.d.ts +3 -0
  7. package/dist/cli/commands/cache-clear.d.ts.map +1 -0
  8. package/dist/cli/commands/cache-clear.js +24 -0
  9. package/dist/cli/commands/cache-clear.js.map +1 -0
  10. package/dist/cli/commands/full.d.ts +3 -0
  11. package/dist/cli/commands/full.d.ts.map +1 -0
  12. package/dist/cli/commands/full.js +37 -0
  13. package/dist/cli/commands/full.js.map +1 -0
  14. package/dist/cli/commands/generate.d.ts +3 -0
  15. package/dist/cli/commands/generate.d.ts.map +1 -0
  16. package/dist/cli/commands/generate.js +53 -0
  17. package/dist/cli/commands/generate.js.map +1 -0
  18. package/dist/cli/commands/init.d.ts +3 -0
  19. package/dist/cli/commands/init.d.ts.map +1 -0
  20. package/dist/cli/commands/init.js +20 -0
  21. package/dist/cli/commands/init.js.map +1 -0
  22. package/dist/cli/commands/live-scan.d.ts +3 -0
  23. package/dist/cli/commands/live-scan.d.ts.map +1 -0
  24. package/dist/cli/commands/{live-scan-command.js → live-scan.js} +22 -16
  25. package/dist/cli/commands/live-scan.js.map +1 -0
  26. package/dist/cli/commands/makeauth.d.ts +3 -0
  27. package/dist/cli/commands/makeauth.d.ts.map +1 -0
  28. package/dist/cli/commands/makeauth.js +76 -0
  29. package/dist/cli/commands/makeauth.js.map +1 -0
  30. package/dist/cli/commands/map.d.ts +3 -0
  31. package/dist/cli/commands/map.d.ts.map +1 -0
  32. package/dist/cli/commands/map.js +93 -0
  33. package/dist/cli/commands/map.js.map +1 -0
  34. package/dist/cli/commands/validate.d.ts +3 -0
  35. package/dist/cli/commands/validate.d.ts.map +1 -0
  36. package/dist/cli/commands/validate.js +43 -0
  37. package/dist/cli/commands/validate.js.map +1 -0
  38. package/dist/cli/index.js +29 -442
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/types.d.ts +9 -0
  41. package/dist/cli/types.d.ts.map +1 -0
  42. package/dist/cli/types.js +7 -0
  43. package/dist/cli/types.js.map +1 -0
  44. package/dist/cli/utils.d.ts +6 -0
  45. package/dist/cli/utils.d.ts.map +1 -0
  46. package/dist/cli/utils.js +101 -0
  47. package/dist/cli/utils.js.map +1 -0
  48. package/dist/core/live-scanner/matrix-reader.d.ts.map +1 -1
  49. package/dist/core/live-scanner/matrix-reader.js +2 -40
  50. package/dist/core/live-scanner/matrix-reader.js.map +1 -1
  51. package/dist/core/live-scanner/scanner.d.ts.map +1 -1
  52. package/dist/core/live-scanner/scanner.js +22 -4
  53. package/dist/core/live-scanner/scanner.js.map +1 -1
  54. package/dist/core/live-scanner/step-replayer.d.ts +1 -1
  55. package/dist/core/live-scanner/step-replayer.d.ts.map +1 -1
  56. package/dist/core/live-scanner/step-replayer.js +107 -6
  57. package/dist/core/live-scanner/step-replayer.js.map +1 -1
  58. package/dist/core/live-scanner/types.d.ts +1 -0
  59. package/dist/core/live-scanner/types.d.ts.map +1 -1
  60. package/dist/core/validator/selector-validator.d.ts.map +1 -1
  61. package/dist/core/validator/selector-validator.js +2 -1
  62. package/dist/core/validator/selector-validator.js.map +1 -1
  63. package/dist/generators/scaffold-generator/index.d.ts +2 -1
  64. package/dist/generators/scaffold-generator/index.d.ts.map +1 -1
  65. package/dist/generators/scaffold-generator/index.js +21 -1
  66. package/dist/generators/scaffold-generator/index.js.map +1 -1
  67. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  68. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  69. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  70. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  71. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  72. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  73. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  74. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  75. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  76. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  77. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  78. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  79. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  80. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  81. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  82. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  83. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  84. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  85. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  86. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  87. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  88. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  89. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  90. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  91. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  92. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  93. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  94. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  95. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  96. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  97. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  98. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  99. package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -58
  100. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  101. package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -2
  102. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
  103. package/dist/generators/test-generator/patterns/form-patterns.js +34 -47
  104. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
  105. package/dist/generators/test-generator/patterns/index.d.ts +3 -1
  106. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  107. package/dist/generators/test-generator/patterns/index.js +20 -3
  108. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  109. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -1
  110. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  111. package/dist/generators/test-generator/patterns/interaction-patterns.js +44 -85
  112. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  113. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +7 -0
  114. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +1 -0
  115. package/dist/generators/test-generator/patterns/legacy-patterns.js +98 -0
  116. package/dist/generators/test-generator/patterns/legacy-patterns.js.map +1 -0
  117. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -2
  118. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
  119. package/dist/generators/test-generator/patterns/navigation-patterns.js +14 -42
  120. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
  121. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -1
  122. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -1
  123. package/dist/generators/test-generator/patterns/setup-patterns.js +23 -35
  124. package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -1
  125. package/dist/generators/test-generator/patterns/types.d.ts +18 -3
  126. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  127. package/dist/generators/test-generator/step-mapper.d.ts +0 -15
  128. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  129. package/dist/generators/test-generator/step-mapper.js +4 -106
  130. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  131. package/dist/{executor/test-generator.d.ts → generators/test-generator/types.d.ts} +4 -25
  132. package/dist/generators/test-generator/types.d.ts.map +1 -0
  133. package/dist/generators/test-generator/types.js +106 -0
  134. package/dist/generators/test-generator/types.js.map +1 -0
  135. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  136. package/dist/generators/test-generator/utils/data-resolver.js +8 -17
  137. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  138. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  139. package/dist/generators/test-generator/utils/selector-resolver.js +10 -18
  140. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  141. package/dist/orchestrator/cache-manager.d.ts +1 -23
  142. package/dist/orchestrator/cache-manager.d.ts.map +1 -1
  143. package/dist/orchestrator/cache-manager.js +1 -87
  144. package/dist/orchestrator/cache-manager.js.map +1 -1
  145. package/dist/orchestrator/pipeline.d.ts +11 -28
  146. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  147. package/dist/orchestrator/pipeline.js +52 -371
  148. package/dist/orchestrator/pipeline.js.map +1 -1
  149. package/dist/orchestrator/reporter.d.ts +1 -1
  150. package/dist/orchestrator/reporter.d.ts.map +1 -1
  151. package/dist/orchestrator/screen-manager.js +1 -1
  152. package/dist/orchestrator/screen-manager.js.map +1 -1
  153. package/dist/utils/feature-finder.d.ts +9 -0
  154. package/dist/utils/feature-finder.d.ts.map +1 -0
  155. package/dist/utils/feature-finder.js +67 -0
  156. package/dist/utils/feature-finder.js.map +1 -0
  157. package/dist/utils/screen-paths.d.ts +10 -0
  158. package/dist/utils/screen-paths.d.ts.map +1 -0
  159. package/dist/utils/screen-paths.js +73 -0
  160. package/dist/utils/screen-paths.js.map +1 -0
  161. package/dist/utils/selector-loader.d.ts +6 -0
  162. package/dist/utils/selector-loader.d.ts.map +1 -0
  163. package/dist/utils/selector-loader.js +20 -0
  164. package/dist/utils/selector-loader.js.map +1 -0
  165. package/dist/utils/selector-types.d.ts +7 -0
  166. package/dist/utils/selector-types.d.ts.map +1 -0
  167. package/dist/utils/selector-types.js +19 -0
  168. package/dist/utils/selector-types.js.map +1 -0
  169. package/dist/utils/test-data-loader.d.ts +6 -0
  170. package/dist/utils/test-data-loader.d.ts.map +1 -0
  171. package/dist/utils/test-data-loader.js +20 -0
  172. package/dist/utils/test-data-loader.js.map +1 -0
  173. package/dist/utils/yaml-io.d.ts +14 -0
  174. package/dist/utils/yaml-io.d.ts.map +1 -0
  175. package/dist/utils/yaml-io.js +72 -0
  176. package/dist/utils/yaml-io.js.map +1 -0
  177. package/package.json +1 -1
  178. package/src/cli/commands/add.ts +25 -0
  179. package/src/cli/commands/cache-clear.ts +22 -0
  180. package/src/cli/commands/full.ts +35 -0
  181. package/src/cli/commands/generate.ts +55 -0
  182. package/src/cli/commands/init.ts +17 -0
  183. package/src/cli/commands/{live-scan-command.ts → live-scan.ts} +21 -18
  184. package/src/cli/commands/makeauth.ts +77 -0
  185. package/src/cli/commands/map.ts +97 -0
  186. package/src/cli/commands/validate.ts +43 -0
  187. package/src/cli/index.ts +32 -473
  188. package/src/cli/types.ts +9 -0
  189. package/src/cli/utils.ts +106 -0
  190. package/src/core/live-scanner/matrix-reader.ts +2 -8
  191. package/src/core/live-scanner/scanner.ts +27 -4
  192. package/src/core/live-scanner/step-replayer.ts +92 -6
  193. package/src/core/live-scanner/types.ts +1 -0
  194. package/src/core/validator/selector-validator.ts +3 -2
  195. package/src/generators/scaffold-generator/index.ts +23 -2
  196. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  197. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  198. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  199. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  200. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  201. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  202. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  203. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  204. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  205. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  206. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  207. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  208. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  209. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  210. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  211. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  212. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  213. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  214. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  215. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  216. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  217. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  218. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  219. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  220. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  221. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  222. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  223. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  224. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  225. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  226. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  227. package/src/generators/test-generator/patterns/assertion-patterns.ts +102 -62
  228. package/src/generators/test-generator/patterns/form-patterns.ts +38 -60
  229. package/src/generators/test-generator/patterns/index.ts +22 -4
  230. package/src/generators/test-generator/patterns/interaction-patterns.ts +47 -107
  231. package/src/generators/test-generator/patterns/legacy-patterns.ts +104 -0
  232. package/src/generators/test-generator/patterns/navigation-patterns.ts +27 -69
  233. package/src/generators/test-generator/patterns/setup-patterns.ts +23 -41
  234. package/src/generators/test-generator/patterns/types.ts +26 -9
  235. package/src/generators/test-generator/step-mapper.ts +4 -124
  236. package/src/generators/test-generator/types.ts +131 -0
  237. package/src/generators/test-generator/utils/data-resolver.ts +8 -13
  238. package/src/generators/test-generator/utils/selector-resolver.ts +15 -17
  239. package/src/orchestrator/cache-manager.ts +1 -107
  240. package/src/orchestrator/pipeline.ts +58 -433
  241. package/src/orchestrator/reporter.ts +1 -1
  242. package/src/orchestrator/screen-manager.ts +1 -1
  243. package/src/utils/feature-finder.ts +33 -0
  244. package/src/utils/screen-paths.ts +37 -0
  245. package/src/utils/selector-loader.ts +23 -0
  246. package/src/utils/selector-types.ts +17 -0
  247. package/src/utils/test-data-loader.ts +23 -0
  248. package/src/utils/yaml-io.ts +33 -0
  249. package/dist/cli/commands/auto-tag-command.d.ts +0 -8
  250. package/dist/cli/commands/auto-tag-command.d.ts.map +0 -1
  251. package/dist/cli/commands/auto-tag-command.js +0 -104
  252. package/dist/cli/commands/auto-tag-command.js.map +0 -1
  253. package/dist/cli/commands/live-scan-command.d.ts +0 -9
  254. package/dist/cli/commands/live-scan-command.d.ts.map +0 -1
  255. package/dist/cli/commands/live-scan-command.js.map +0 -1
  256. package/dist/executor/playwright/playwright-generator.d.ts +0 -33
  257. package/dist/executor/playwright/playwright-generator.d.ts.map +0 -1
  258. package/dist/executor/playwright/playwright-generator.js +0 -136
  259. package/dist/executor/playwright/playwright-generator.js.map +0 -1
  260. package/dist/executor/test-generator.d.ts.map +0 -1
  261. package/dist/executor/test-generator.js +0 -30
  262. package/dist/executor/test-generator.js.map +0 -1
  263. package/dist/generators/cli.d.ts +0 -7
  264. package/dist/generators/cli.d.ts.map +0 -1
  265. package/dist/generators/cli.js +0 -570
  266. package/dist/generators/cli.js.map +0 -1
  267. package/dist/input/cli-adapter.d.ts +0 -75
  268. package/dist/input/cli-adapter.d.ts.map +0 -1
  269. package/dist/input/cli-adapter.js +0 -218
  270. package/dist/input/cli-adapter.js.map +0 -1
  271. package/dist/input/config-adapter.d.ts +0 -25
  272. package/dist/input/config-adapter.d.ts.map +0 -1
  273. package/dist/input/config-adapter.js +0 -70
  274. package/dist/input/config-adapter.js.map +0 -1
  275. package/dist/input/input-adapter.d.ts +0 -28
  276. package/dist/input/input-adapter.d.ts.map +0 -1
  277. package/dist/input/input-adapter.js +0 -17
  278. package/dist/input/input-adapter.js.map +0 -1
  279. package/dist/input/vscode-adapter.d.ts +0 -62
  280. package/dist/input/vscode-adapter.d.ts.map +0 -1
  281. package/dist/input/vscode-adapter.js +0 -64
  282. package/dist/input/vscode-adapter.js.map +0 -1
  283. package/dist/tools/auto-tagger.d.ts +0 -107
  284. package/dist/tools/auto-tagger.d.ts.map +0 -1
  285. package/dist/tools/auto-tagger.js +0 -502
  286. package/dist/tools/auto-tagger.js.map +0 -1
  287. package/src/cli/commands/auto-tag-command.ts +0 -80
  288. package/src/executor/playwright/playwright-generator.ts +0 -125
  289. package/src/executor/test-generator.ts +0 -90
  290. package/src/generators/cli.ts +0 -640
  291. package/src/input/cli-adapter.ts +0 -233
  292. package/src/input/config-adapter.ts +0 -71
  293. package/src/input/input-adapter.ts +0 -32
  294. package/src/input/vscode-adapter.ts +0 -90
  295. package/src/tools/auto-tagger.ts +0 -572
@@ -9,6 +9,7 @@ import { glob } from 'glob';
9
9
  import { LiveScanResult, LiveScanScenario, LiveScanOptions } from './types';
10
10
  import { replaySteps } from './step-replayer';
11
11
  import { writeMatrix } from './matrix-writer';
12
+ import { readMatrix, mergeMatrixElements } from './matrix-reader';
12
13
  import { readBaseUrlFromPlaywrightConfig } from './config-reader';
13
14
 
14
15
  export class LiveScanner {
@@ -68,9 +69,19 @@ export class LiveScanner {
68
69
  const featureName = path.basename(featureFile, '.feature');
69
70
  console.log(`\n📄 Scanning feature: ${featureName}`);
70
71
 
72
+ // Load existing matrix for incremental scan (non-force mode)
73
+ let existingResult: LiveScanResult | null = null;
74
+ if (!this.options.force) {
75
+ const matrixPath = path.join(selectorsDir, `${featureName}.live-scan.yaml`);
76
+ existingResult = readMatrix(matrixPath);
77
+ if (existingResult) {
78
+ console.log(` 📦 Found existing scan — resolved elements will be skipped`);
79
+ }
80
+ }
81
+
71
82
  try {
72
83
  const parsed = parser.parseFeatureFile(featureFile);
73
- const result = await this.scanFeature(browser, playwright, parsed, baseUrl);
84
+ const result = await this.scanFeature(browser, playwright, parsed, baseUrl, existingResult);
74
85
  results.push(result);
75
86
 
76
87
  // Write matrix file
@@ -112,11 +123,15 @@ export class LiveScanner {
112
123
  browser: any,
113
124
  playwright: any,
114
125
  feature: any,
115
- baseUrl: string
126
+ baseUrl: string,
127
+ existingResult?: LiveScanResult | null
116
128
  ): Promise<LiveScanResult> {
117
129
  const featurePath = feature.path || '/';
118
130
  const scenarios: Record<string, LiveScanScenario> = {};
119
131
 
132
+ // Build merged existing elements map for skip logic
133
+ const existingElements = existingResult ? mergeMatrixElements(existingResult) : undefined;
134
+
120
135
  // Build a map of @steps scenarios for resolution
121
136
  const stepsMap = new Map<string, any>();
122
137
  for (const scenario of feature.scenarios) {
@@ -167,7 +182,7 @@ export class LiveScanner {
167
182
  const page = await context.newPage();
168
183
 
169
184
  try {
170
- const result = await replaySteps(page, steps, featurePath, baseUrl);
185
+ const result = await replaySteps(page, steps, featurePath, baseUrl, existingElements);
171
186
 
172
187
  scenarios[scenarioKey] = {
173
188
  auth: authRole,
@@ -178,6 +193,9 @@ export class LiveScanner {
178
193
 
179
194
  // Print element summary
180
195
  const elementCount = Object.keys(result.elements).length;
196
+ const skipped = Object.values(result.elements).filter(
197
+ (e: any) => e.skipped
198
+ ).length;
181
199
  const resolved = Object.values(result.elements).filter(
182
200
  (e: any) => e.matchMethod !== 'unresolved'
183
201
  ).length;
@@ -185,7 +203,8 @@ export class LiveScanner {
185
203
  (e: any) => e.warning
186
204
  ).length;
187
205
 
188
- console.log(` 📊 Elements: ${resolved}/${elementCount} resolved${warnings > 0 ? `, ${warnings} warnings` : ''}`);
206
+ const skippedInfo = skipped > 0 ? `, ${skipped} cached` : '';
207
+ console.log(` 📊 Elements: ${resolved}/${elementCount} resolved${skippedInfo}${warnings > 0 ? `, ${warnings} warnings` : ''}`);
189
208
 
190
209
  for (const error of result.errors) {
191
210
  console.log(` ⚠️ ${error}`);
@@ -193,6 +212,10 @@ export class LiveScanner {
193
212
 
194
213
  // Print per-element status
195
214
  for (const [key, el] of Object.entries(result.elements) as any) {
215
+ if (el.skipped) {
216
+ // Already printed in replaySteps
217
+ continue;
218
+ }
196
219
  if (el.matchMethod === 'unresolved') {
197
220
  console.log(` ✗ [${el.gherkinRef}] ${el.gherkinType} → NOT FOUND`);
198
221
  } else if (el.warning) {
@@ -31,12 +31,33 @@ export async function replaySteps(
31
31
  page: Page,
32
32
  steps: ParsedStepInfo[],
33
33
  featurePath: string,
34
- baseUrl: string
34
+ baseUrl: string,
35
+ existingElements?: Record<string, LiveElement>
35
36
  ): Promise<ReplayResult> {
36
37
  const elements: Record<string, LiveElement> = {};
37
38
  const errors: string[] = [];
38
39
  let currentContext: ElementContext = 'page';
39
40
 
41
+ // Pre-scan: detect which base keys have multiple normalized element types
42
+ // so we can append --type suffix (matching scaffold generator behavior)
43
+ // Uses normalizeElementType to match scaffold generator's extractTargetType mapping
44
+ // e.g. modal/dialog both normalize to 'dialog', so they won't create a false conflict
45
+ const typesPerKey = new Map<string, Set<string>>();
46
+ for (const step of steps) {
47
+ if (!step.selectorRef) continue;
48
+ const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
49
+ const action = detectAction(step.text);
50
+ const normalizedType = normalizeElementType(step.elementType || 'button', action);
51
+ if (!typesPerKey.has(baseKey)) {
52
+ typesPerKey.set(baseKey, new Set());
53
+ }
54
+ typesPerKey.get(baseKey)!.add(normalizedType);
55
+ }
56
+ const conflictKeys = new Set<string>();
57
+ for (const [key, types] of typesPerKey) {
58
+ if (types.size > 1) conflictKeys.add(key);
59
+ }
60
+
40
61
  for (const step of steps) {
41
62
  try {
42
63
  const action = detectAction(step.text);
@@ -46,7 +67,9 @@ export async function replaySteps(
46
67
  await page.goto(baseUrl + featurePath, { waitUntil: 'networkidle', timeout: 15000 });
47
68
  await settle(page);
48
69
  if (step.selectorRef) {
49
- const key = generateElementKey(step.selectorRef, step.elementType);
70
+ const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
71
+ const normalizedType = normalizeElementType(step.elementType || 'page', action);
72
+ const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
50
73
  // Record the page element but don't search for it on the DOM
51
74
  elements[key] = {
52
75
  gherkinRef: step.selectorRef,
@@ -71,9 +94,36 @@ export async function replaySteps(
71
94
  // Skip steps without element references
72
95
  if (!step.selectorRef) continue;
73
96
 
74
- const key = generateElementKey(step.selectorRef, step.elementType);
75
- const nth = step.nth || 0;
97
+ const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
76
98
  const elementType = step.elementType || 'button';
99
+ const normalizedType = normalizeElementType(elementType, action);
100
+ const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
101
+ const nth = step.nth || 0;
102
+
103
+ // Skip column-type elements — they use header text matching, no DOM lookup needed
104
+ if (normalizedType === 'column') {
105
+ console.log(` ⏭️ [${step.selectorRef}] column → skipped (table header match)`);
106
+ continue;
107
+ }
108
+
109
+ // Skip if element already resolved in existing scan (non-force mode)
110
+ if (existingElements && existingElements[key] && existingElements[key].matchMethod !== 'unresolved') {
111
+ elements[key] = existingElements[key];
112
+ (elements[key] as any).skipped = true;
113
+ console.log(` ⏩ [${step.selectorRef}] ${elementType} → cached (${existingElements[key].selectorType})`);
114
+
115
+ // Still execute clicks for cached elements to maintain page state
116
+ if (action === 'click') {
117
+ try {
118
+ await executeClick(page, step.selectorRef, elementType, nth);
119
+ await settle(page);
120
+ currentContext = await detectCurrentContext(page, currentContext, step.text);
121
+ } catch {
122
+ // Click failed for cached element, continue anyway
123
+ }
124
+ }
125
+ continue;
126
+ }
77
127
 
78
128
  // Find the element on the page
79
129
  const element = await findElement(page, step.selectorRef, elementType, nth);
@@ -208,10 +258,46 @@ async function settle(page: Page): Promise<void> {
208
258
  await page.waitForTimeout(300);
209
259
  }
210
260
 
211
- function generateElementKey(ref: string, elementType?: string): string {
261
+ function generateElementKey(ref: string, elementType?: string, nth?: number): string {
212
262
  // Use the same key generation as the scaffold generator
213
263
  // so live-scan keys match scaffold keys in the map command.
214
- return SelectorResolver.generateKey(ref);
264
+ // Append --N suffix for nth > 0, consistent with scaffold generator format.
265
+ const baseKey = SelectorResolver.generateKey(ref);
266
+ return nth && nth > 0 ? `${baseKey}--${nth}` : baseKey;
267
+ }
268
+
269
+ /**
270
+ * Normalize element type to match scaffold generator's extractTargetType() mapping.
271
+ * e.g. modal→dialog, img/icon/logo→img, input→field, select→dropdown, etc.
272
+ */
273
+ function normalizeElementType(elementType: string, action: string): string {
274
+ const t = elementType.toLowerCase();
275
+ if (t === 'page') return 'page';
276
+ if (t === 'link') return 'link';
277
+ if (t === 'button') return 'button';
278
+ if (t === 'radio') return 'radio';
279
+ if (t === 'dropdown' || t === 'select') return 'dropdown';
280
+ if (t === 'checkbox') return 'checkbox';
281
+ if (t === 'field' || t === 'input') return 'field';
282
+ if (t === 'textbox') return 'textbox';
283
+ if (t === 'textarea') return 'textarea';
284
+ if (t === 'text') return 'text';
285
+ if (t === 'label') return 'label';
286
+ if (t === 'uploader') return 'uploader';
287
+ if (t === 'element') return 'element';
288
+ if (t === 'column' || t === 'columnheader') return 'column';
289
+ if (t === 'logo' || t === 'image' || t === 'img' || t === 'icon') return 'img';
290
+ if (t === 'dialog' || t === 'modal') return 'dialog';
291
+ if (t === 'heading' || t === 'header') return 'heading';
292
+ if (t === 'title' || t === 'caption' || t === 'message') return 'text';
293
+ // Default based on action (matches scaffold generator)
294
+ switch (action) {
295
+ case 'click': return 'text';
296
+ case 'fill': return 'field';
297
+ case 'see': return 'text';
298
+ case 'select': return 'dropdown';
299
+ default: return 'element';
300
+ }
215
301
  }
216
302
 
217
303
  function escapeRegex(str: string): string {
@@ -53,4 +53,5 @@ export interface LiveScanOptions {
53
53
  screensDir: string;
54
54
  headed?: boolean;
55
55
  authDir?: string;
56
+ force?: boolean;
56
57
  }
@@ -8,10 +8,11 @@ import * as path from 'path';
8
8
  import yaml from 'yaml';
9
9
  import { ValidationIssue } from './index';
10
10
  import { SelectorResolver } from '../../generators/test-generator/utils/selector-resolver';
11
+ import { VALID_SELECTOR_TYPES, SelectorType } from '../../utils/selector-types';
11
12
 
12
13
  interface SelectorEntry {
13
14
  selector?: string;
14
- type?: 'placeholder' | 'role' | 'testid' | 'label' | 'text' | 'page';
15
+ type?: SelectorType;
15
16
  value?: string;
16
17
  name?: string;
17
18
  nth?: number;
@@ -19,7 +20,7 @@ interface SelectorEntry {
19
20
 
20
21
  type SelectorFile = Record<string, SelectorEntry>;
21
22
 
22
- const VALID_TYPES = ['placeholder', 'role', 'testid', 'label', 'text', 'page'];
23
+ const VALID_TYPES = VALID_SELECTOR_TYPES;
23
24
 
24
25
  export class SelectorValidator {
25
26
  private screenName: string;
@@ -8,10 +8,11 @@ import path from 'path';
8
8
  import yaml from 'yaml';
9
9
  import { glob } from 'glob';
10
10
  import { SelectorResolver } from '../test-generator/utils/selector-resolver';
11
+ import { SelectorType } from '../../utils/selector-types';
11
12
 
12
13
  export interface ScaffoldElement {
13
14
  locator: string;
14
- type: 'placeholder' | 'role' | 'text' | 'label' | 'page' | 'testid';
15
+ type: SelectorType;
15
16
  value: string;
16
17
  name?: string; // For role type (accessible name), or label text
17
18
  nth: number;
@@ -176,6 +177,9 @@ export class ScaffoldGenerator {
176
177
  if (/^element\b/.test(lowerText) || /^\d*\s*element\b/.test(lowerText)) {
177
178
  return 'element';
178
179
  }
180
+ if (/^(column|columnheader)\b/.test(lowerText) || /^\d*\s*(column|columnheader)\b/.test(lowerText)) {
181
+ return 'column';
182
+ }
179
183
  if (/^(logo|image|img|icon)\b/.test(lowerText) || /^\d*\s*(logo|image|img|icon)\b/.test(lowerText)) {
180
184
  return 'img';
181
185
  }
@@ -395,9 +399,19 @@ export class ScaffoldGenerator {
395
399
  };
396
400
 
397
401
  case 'see':
402
+ // Column type: used for table column cell assertions, no DOM selector needed
403
+ if (targetType === 'column') {
404
+ return {
405
+ locator: '',
406
+ type: 'column',
407
+ value: element.rawText,
408
+ nth,
409
+ };
410
+ }
411
+
398
412
  // For assertions - respect targetType for role-based elements
399
413
  if (targetType === 'img' || targetType === 'button' || targetType === 'link' ||
400
- targetType === 'checkbox' || targetType === 'radio' || targetType === 'heading' || targetType === 'dialog') {
414
+ targetType === 'checkbox' || targetType === 'radio' || targetType === 'heading' || targetType === 'dialog' || targetType === 'dropdown') {
401
415
  const seeRoleValue = this.getRoleValue(targetType);
402
416
  return {
403
417
  locator: '',
@@ -469,6 +483,8 @@ export class ScaffoldGenerator {
469
483
  return 'heading';
470
484
  case 'dialog':
471
485
  return 'dialog';
486
+ case 'dropdown':
487
+ return 'button';
472
488
  default:
473
489
  return 'button'; // Default to button
474
490
  }
@@ -643,6 +659,11 @@ export class ScaffoldGenerator {
643
659
  const enriched: ScaffoldResult = { ...scaffold };
644
660
 
645
661
  for (const [key, scaffoldElement] of Object.entries(enriched)) {
662
+ // Column-type elements use header text matching, skip live-scan enrichment
663
+ if (scaffoldElement.type === 'column') continue;
664
+ // Target elements (empty value) are matched by data value at runtime, skip enrichment
665
+ if (!scaffoldElement.value && !scaffoldElement.name) continue;
666
+
646
667
  // Try exact key first, then base key without --N suffix or --type suffix
647
668
  let liveElement = elements[key];
648
669
  if (!liveElement && key.includes('--')) {
@@ -0,0 +1,2 @@
1
+ await {{> locator}}.click();
2
+ await page.getByText('{{selectValue}}', { exact: true }).first().click();
@@ -0,0 +1 @@
1
+ await page.getByRole('{{role}}').filter({ hasText: '{{escapeQuotes dataValue}}' }).waitFor({ state: '{{state}}' });
@@ -0,0 +1 @@
1
+ await page.getByRole('{{role}}').waitFor({ state: '{{state}}' });
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeChecked();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeChecked();
@@ -0,0 +1,3 @@
1
+ await page.waitForLoadState('networkidle');
2
+ const {{columnIndexVar}} = (await page.getByRole('columnheader').allTextContents()).findIndex(h => h.includes('{{columnName}}'));
3
+ await expect(page.getByRole('row').nth({{rowNth}}).getByRole('cell').nth({{columnIndexVar}})).toHaveText('{{dataValue}}');
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toContainText('{{expectedText}}');
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toContainText('{{expectedText}}');
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toHaveCount({{expectedCount}});
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toHaveCount({{expectedCount}});
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeDisabled();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeDisabled();
@@ -1 +1,2 @@
1
- await expect({{> locator-base}}.filter({ hasText: '{{escapeQuotes dataValue}}' }){{> locator-nth}}).toBeDisabled();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeDisabled();
@@ -1,5 +1,6 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  {{#if name}}
2
- await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
3
+ await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
3
4
  {{else}}
4
- await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
5
- {{/if}}
5
+ await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
6
+ {{/if}}
@@ -1 +1,2 @@
1
- await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeEmpty();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeEmpty();
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeEnabled();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeEnabled();
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeFocused();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeFocused();
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toHaveText('{{expectedText}}');
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toHaveText('{{expectedText}}');
@@ -0,0 +1,2 @@
1
+ await page.waitForLoadState('networkidle');
2
+ await expect(page.getByRole('dialog').getByRole('heading', { name: '{{escapeQuotes dataValue}}' })).toBeHidden();
@@ -1 +1,2 @@
1
- await expect({{> locator-base}}.filter({ hasText: '{{escapeQuotes dataValue}}' }){{> locator-nth}}).toBeHidden();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeHidden();
@@ -1,5 +1,6 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  {{#if name}}
2
- await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
3
+ await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
3
4
  {{else}}
4
- await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
5
- {{/if}}
5
+ await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
6
+ {{/if}}
@@ -1 +1,2 @@
1
- await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
@@ -1 +1,2 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  await expect({{> locator}}).toBeHidden();
@@ -1 +1,2 @@
1
- await expect({{> locator}}.getByRole('listitem')).toHaveCount({{expectedCount}});
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}.getByRole('listitem')).toHaveCount({{expectedCount}});
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeChecked({ checked: false });
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeChecked({ checked: false });
@@ -1 +1,2 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  await expect(page).toHaveURL(/{{pathRegex}}/);
@@ -1 +1,2 @@
1
- await expect({{> locator}}).toBeVisible();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator}}).toBeVisible();
@@ -0,0 +1,2 @@
1
+ await page.waitForLoadState('networkidle');
2
+ await expect(page.getByRole('dialog').getByRole('heading', { name: '{{escapeQuotes dataValue}}' })).toBeVisible();
@@ -1 +1,2 @@
1
- await expect({{> locator-base}}.filter({ hasText: '{{escapeQuotes dataValue}}' }){{> locator-nth}}).toBeVisible();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeVisible();
@@ -1,9 +1,10 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  {{#if name}}
2
3
  {{#if dataValue}}
3
- await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
4
+ await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
4
5
  {{else}}
5
6
  await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
6
7
  {{/if}}
7
8
  {{else}}
8
- await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: '{{escapeQuotes dataValue}}' }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
9
- {{/if}}
9
+ await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
10
+ {{/if}}
@@ -1 +1,2 @@
1
- await expect(page.getByText('{{escapeQuotes value}}').filter({ hasText: '{{escapeQuotes dataValue}}' })).toBeVisible();
1
+ await page.waitForLoadState('networkidle');
2
+ await expect(page.getByText('{{escapeQuotes value}}').filter({ hasText: /^{{escapeRegex dataValue}}$/ })).toBeVisible();
@@ -1 +1,2 @@
1
+ await page.waitForLoadState('networkidle');
1
2
  await expect(page.getByText('{{escapeQuotes selectorValue}}').filter({ hasText: /.*{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
@@ -1 +1 @@
1
- await page.goto('{{#if baseURL}}{{baseURL}}{{/if}}{{path}}');
1
+ await page.goto('{{#if baseURL}}{{baseURL}}{{/if}}{{path}}', { waitUntil: 'networkidle' });
@@ -1 +1 @@
1
- await {{> locator-base}}.filter({ hasText: '{{escapeQuotes dataValue}}' }){{> locator-nth}}.waitFor({ state: '{{state}}' });
1
+ await {{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}.waitFor({ state: '{{state}}' });