@sun-asterisk/sungen 1.0.20 → 1.0.22

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 (294) 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/element-finder.d.ts.map +1 -1
  48. package/dist/core/live-scanner/element-finder.js +138 -22
  49. package/dist/core/live-scanner/element-finder.js.map +1 -1
  50. package/dist/core/live-scanner/matrix-reader.d.ts.map +1 -1
  51. package/dist/core/live-scanner/matrix-reader.js +2 -40
  52. package/dist/core/live-scanner/matrix-reader.js.map +1 -1
  53. package/dist/core/live-scanner/matrix-writer.d.ts.map +1 -1
  54. package/dist/core/live-scanner/matrix-writer.js +14 -4
  55. package/dist/core/live-scanner/matrix-writer.js.map +1 -1
  56. package/dist/core/live-scanner/step-replayer.d.ts.map +1 -1
  57. package/dist/core/live-scanner/step-replayer.js +7 -0
  58. package/dist/core/live-scanner/step-replayer.js.map +1 -1
  59. package/dist/core/validator/selector-validator.d.ts.map +1 -1
  60. package/dist/core/validator/selector-validator.js +2 -1
  61. package/dist/core/validator/selector-validator.js.map +1 -1
  62. package/dist/generators/scaffold-generator/index.d.ts +2 -1
  63. package/dist/generators/scaffold-generator/index.d.ts.map +1 -1
  64. package/dist/generators/scaffold-generator/index.js +21 -1
  65. package/dist/generators/scaffold-generator/index.js.map +1 -1
  66. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  67. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  68. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  69. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  70. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  71. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  72. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  73. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  74. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  75. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  76. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  77. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  78. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  79. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  80. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  81. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  82. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  83. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  84. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  85. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  86. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  87. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  88. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  89. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  90. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  91. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  92. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  93. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  94. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  95. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  96. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  97. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  98. package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -58
  99. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  100. package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -2
  101. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
  102. package/dist/generators/test-generator/patterns/form-patterns.js +34 -47
  103. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
  104. package/dist/generators/test-generator/patterns/index.d.ts +3 -1
  105. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  106. package/dist/generators/test-generator/patterns/index.js +20 -3
  107. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  108. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -1
  109. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  110. package/dist/generators/test-generator/patterns/interaction-patterns.js +44 -85
  111. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  112. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +7 -0
  113. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +1 -0
  114. package/dist/generators/test-generator/patterns/legacy-patterns.js +98 -0
  115. package/dist/generators/test-generator/patterns/legacy-patterns.js.map +1 -0
  116. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -2
  117. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
  118. package/dist/generators/test-generator/patterns/navigation-patterns.js +14 -42
  119. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
  120. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -1
  121. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -1
  122. package/dist/generators/test-generator/patterns/setup-patterns.js +23 -35
  123. package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -1
  124. package/dist/generators/test-generator/patterns/types.d.ts +18 -3
  125. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  126. package/dist/generators/test-generator/step-mapper.d.ts +0 -15
  127. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  128. package/dist/generators/test-generator/step-mapper.js +4 -106
  129. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  130. package/dist/{executor/test-generator.d.ts → generators/test-generator/types.d.ts} +4 -25
  131. package/dist/generators/test-generator/types.d.ts.map +1 -0
  132. package/dist/generators/test-generator/types.js +106 -0
  133. package/dist/generators/test-generator/types.js.map +1 -0
  134. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  135. package/dist/generators/test-generator/utils/data-resolver.js +8 -17
  136. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  137. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  138. package/dist/generators/test-generator/utils/selector-resolver.js +10 -18
  139. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  140. package/dist/orchestrator/cache-manager.d.ts +1 -23
  141. package/dist/orchestrator/cache-manager.d.ts.map +1 -1
  142. package/dist/orchestrator/cache-manager.js +1 -87
  143. package/dist/orchestrator/cache-manager.js.map +1 -1
  144. package/dist/orchestrator/pipeline.d.ts +11 -28
  145. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  146. package/dist/orchestrator/pipeline.js +52 -371
  147. package/dist/orchestrator/pipeline.js.map +1 -1
  148. package/dist/orchestrator/reporter.d.ts +1 -1
  149. package/dist/orchestrator/reporter.d.ts.map +1 -1
  150. package/dist/orchestrator/screen-manager.js +1 -1
  151. package/dist/orchestrator/screen-manager.js.map +1 -1
  152. package/dist/utils/feature-finder.d.ts +9 -0
  153. package/dist/utils/feature-finder.d.ts.map +1 -0
  154. package/dist/utils/feature-finder.js +67 -0
  155. package/dist/utils/feature-finder.js.map +1 -0
  156. package/dist/utils/screen-paths.d.ts +10 -0
  157. package/dist/utils/screen-paths.d.ts.map +1 -0
  158. package/dist/utils/screen-paths.js +73 -0
  159. package/dist/utils/screen-paths.js.map +1 -0
  160. package/dist/utils/selector-loader.d.ts +6 -0
  161. package/dist/utils/selector-loader.d.ts.map +1 -0
  162. package/dist/utils/selector-loader.js +20 -0
  163. package/dist/utils/selector-loader.js.map +1 -0
  164. package/dist/utils/selector-types.d.ts +7 -0
  165. package/dist/utils/selector-types.d.ts.map +1 -0
  166. package/dist/utils/selector-types.js +19 -0
  167. package/dist/utils/selector-types.js.map +1 -0
  168. package/dist/utils/test-data-loader.d.ts +6 -0
  169. package/dist/utils/test-data-loader.d.ts.map +1 -0
  170. package/dist/utils/test-data-loader.js +20 -0
  171. package/dist/utils/test-data-loader.js.map +1 -0
  172. package/dist/utils/yaml-io.d.ts +14 -0
  173. package/dist/utils/yaml-io.d.ts.map +1 -0
  174. package/dist/utils/yaml-io.js +72 -0
  175. package/dist/utils/yaml-io.js.map +1 -0
  176. package/package.json +1 -1
  177. package/src/cli/commands/add.ts +25 -0
  178. package/src/cli/commands/cache-clear.ts +22 -0
  179. package/src/cli/commands/full.ts +35 -0
  180. package/src/cli/commands/generate.ts +55 -0
  181. package/src/cli/commands/init.ts +17 -0
  182. package/src/cli/commands/{live-scan-command.ts → live-scan.ts} +8 -17
  183. package/src/cli/commands/makeauth.ts +77 -0
  184. package/src/cli/commands/map.ts +97 -0
  185. package/src/cli/commands/validate.ts +43 -0
  186. package/src/cli/index.ts +32 -473
  187. package/src/cli/types.ts +9 -0
  188. package/src/cli/utils.ts +106 -0
  189. package/src/core/live-scanner/element-finder.ts +142 -21
  190. package/src/core/live-scanner/matrix-reader.ts +2 -8
  191. package/src/core/live-scanner/matrix-writer.ts +14 -4
  192. package/src/core/live-scanner/step-replayer.ts +7 -0
  193. package/src/core/validator/selector-validator.ts +3 -2
  194. package/src/generators/scaffold-generator/index.ts +23 -2
  195. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  196. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  197. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  198. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  199. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  200. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  201. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  202. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  203. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  204. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  205. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  206. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  207. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  208. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  209. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  210. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  211. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  212. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  213. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  214. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  215. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  216. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  217. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  218. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  219. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  220. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  221. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  222. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  223. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  224. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  225. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  226. package/src/generators/test-generator/patterns/assertion-patterns.ts +102 -62
  227. package/src/generators/test-generator/patterns/form-patterns.ts +38 -60
  228. package/src/generators/test-generator/patterns/index.ts +22 -4
  229. package/src/generators/test-generator/patterns/interaction-patterns.ts +47 -107
  230. package/src/generators/test-generator/patterns/legacy-patterns.ts +104 -0
  231. package/src/generators/test-generator/patterns/navigation-patterns.ts +27 -69
  232. package/src/generators/test-generator/patterns/setup-patterns.ts +23 -41
  233. package/src/generators/test-generator/patterns/types.ts +26 -9
  234. package/src/generators/test-generator/step-mapper.ts +4 -124
  235. package/src/generators/test-generator/types.ts +131 -0
  236. package/src/generators/test-generator/utils/data-resolver.ts +8 -13
  237. package/src/generators/test-generator/utils/selector-resolver.ts +15 -17
  238. package/src/orchestrator/cache-manager.ts +1 -107
  239. package/src/orchestrator/pipeline.ts +58 -433
  240. package/src/orchestrator/reporter.ts +1 -1
  241. package/src/orchestrator/screen-manager.ts +1 -1
  242. package/src/utils/feature-finder.ts +33 -0
  243. package/src/utils/screen-paths.ts +37 -0
  244. package/src/utils/selector-loader.ts +23 -0
  245. package/src/utils/selector-types.ts +17 -0
  246. package/src/utils/test-data-loader.ts +23 -0
  247. package/src/utils/yaml-io.ts +33 -0
  248. package/dist/cli/commands/auto-tag-command.d.ts +0 -8
  249. package/dist/cli/commands/auto-tag-command.d.ts.map +0 -1
  250. package/dist/cli/commands/auto-tag-command.js +0 -104
  251. package/dist/cli/commands/auto-tag-command.js.map +0 -1
  252. package/dist/cli/commands/live-scan-command.d.ts +0 -9
  253. package/dist/cli/commands/live-scan-command.d.ts.map +0 -1
  254. package/dist/cli/commands/live-scan-command.js.map +0 -1
  255. package/dist/executor/playwright/playwright-generator.d.ts +0 -33
  256. package/dist/executor/playwright/playwright-generator.d.ts.map +0 -1
  257. package/dist/executor/playwright/playwright-generator.js +0 -136
  258. package/dist/executor/playwright/playwright-generator.js.map +0 -1
  259. package/dist/executor/test-generator.d.ts.map +0 -1
  260. package/dist/executor/test-generator.js +0 -30
  261. package/dist/executor/test-generator.js.map +0 -1
  262. package/dist/generators/cli.d.ts +0 -7
  263. package/dist/generators/cli.d.ts.map +0 -1
  264. package/dist/generators/cli.js +0 -570
  265. package/dist/generators/cli.js.map +0 -1
  266. package/dist/input/cli-adapter.d.ts +0 -75
  267. package/dist/input/cli-adapter.d.ts.map +0 -1
  268. package/dist/input/cli-adapter.js +0 -218
  269. package/dist/input/cli-adapter.js.map +0 -1
  270. package/dist/input/config-adapter.d.ts +0 -25
  271. package/dist/input/config-adapter.d.ts.map +0 -1
  272. package/dist/input/config-adapter.js +0 -70
  273. package/dist/input/config-adapter.js.map +0 -1
  274. package/dist/input/input-adapter.d.ts +0 -28
  275. package/dist/input/input-adapter.d.ts.map +0 -1
  276. package/dist/input/input-adapter.js +0 -17
  277. package/dist/input/input-adapter.js.map +0 -1
  278. package/dist/input/vscode-adapter.d.ts +0 -62
  279. package/dist/input/vscode-adapter.d.ts.map +0 -1
  280. package/dist/input/vscode-adapter.js +0 -64
  281. package/dist/input/vscode-adapter.js.map +0 -1
  282. package/dist/tools/auto-tagger.d.ts +0 -107
  283. package/dist/tools/auto-tagger.d.ts.map +0 -1
  284. package/dist/tools/auto-tagger.js +0 -502
  285. package/dist/tools/auto-tagger.js.map +0 -1
  286. package/src/cli/commands/auto-tag-command.ts +0 -80
  287. package/src/executor/playwright/playwright-generator.ts +0 -125
  288. package/src/executor/test-generator.ts +0 -90
  289. package/src/generators/cli.ts +0 -640
  290. package/src/input/cli-adapter.ts +0 -233
  291. package/src/input/config-adapter.ts +0 -71
  292. package/src/input/input-adapter.ts +0 -32
  293. package/src/input/vscode-adapter.ts +0 -90
  294. package/src/tools/auto-tagger.ts +0 -572
@@ -50,17 +50,19 @@ export async function findElement(
50
50
  try {
51
51
  playwrightName = await result.locator.evaluate((el) => {
52
52
  // computedRole/computedLabel not available in all browsers, fallback to aria
53
- return (el as any).computedName
53
+ const raw = (el as any).computedName
54
54
  || el.getAttribute('aria-label')
55
55
  || el.textContent?.trim()?.substring(0, 100)
56
56
  || '';
57
+ return raw.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
57
58
  });
58
59
  // Better approach: use Playwright's accessibility snapshot
59
60
  const ariaSnapshot = await result.locator.ariaSnapshot();
60
61
  // Parse accessible name from snapshot (format: "- role \"name\"" or "- role \"name\": ...")
61
- const nameMatch = ariaSnapshot?.match(/"([^"]+)"/);
62
+ // Regex handles escaped quotes (\") inside the name string
63
+ const nameMatch = ariaSnapshot?.match(/"((?:[^"\\]|\\.)*)"/);
62
64
  if (nameMatch) {
63
- playwrightName = nameMatch[1];
65
+ playwrightName = unescapeAriaSnapshot(nameMatch[1]);
64
66
  }
65
67
  } catch {
66
68
  playwrightName = attrs.accessibleName || gherkinRef;
@@ -103,7 +105,7 @@ async function cascadingSearch(
103
105
  // ② getByRole — exact role match
104
106
  const roles = getRoleFallbacks(gherkinType);
105
107
  if (roles.length > 0) {
106
- const exactResult = await tryRole(page, roles[0], namePattern, nth);
108
+ const exactResult = await tryRole(page, roles[0], gherkinRef, namePattern, nth);
107
109
  if (exactResult) {
108
110
  return {
109
111
  ...exactResult,
@@ -114,7 +116,7 @@ async function cascadingSearch(
114
116
 
115
117
  // ③ getByRole — fallback roles
116
118
  for (let i = 1; i < roles.length; i++) {
117
- const fallbackResult = await tryRole(page, roles[i], namePattern, nth);
119
+ const fallbackResult = await tryRole(page, roles[i], gherkinRef, namePattern, nth);
118
120
  if (fallbackResult) {
119
121
  return {
120
122
  ...fallbackResult,
@@ -126,16 +128,16 @@ async function cascadingSearch(
126
128
  }
127
129
 
128
130
  // ④ getByLabel — for form elements
129
- const labelResult = await tryLabel(page, namePattern, nth);
131
+ const labelResult = await tryLabel(page, gherkinRef, namePattern, nth);
130
132
  if (labelResult) return labelResult;
131
133
 
132
134
  // ⑤ getByPlaceholder — for input fields
133
- const placeholderResult = await tryPlaceholder(page, namePattern, nth);
135
+ const placeholderResult = await tryPlaceholder(page, gherkinRef, namePattern, nth);
134
136
  if (placeholderResult) return placeholderResult;
135
137
  }
136
138
 
137
139
  // ⑥ getByText — final fallback
138
- const textResult = await tryText(page, namePattern, nth);
140
+ const textResult = await tryText(page, gherkinRef, namePattern, nth);
139
141
  if (textResult) return textResult;
140
142
 
141
143
  return null;
@@ -171,13 +173,36 @@ async function tryTestId(page: Page, ref: string, nth: number): Promise<FindResu
171
173
  return null;
172
174
  }
173
175
 
174
- // ② ③ getByRole
176
+ // ② ③ getByRole — exact string first, then regex fallback
175
177
  async function tryRole(
176
178
  page: Page,
177
179
  role: string,
180
+ gherkinRef: string,
178
181
  namePattern: RegExp,
179
182
  nth: number
180
183
  ): Promise<FindResult | null> {
184
+ // Step 1: Exact string match (prevents short refs matching longer names)
185
+ try {
186
+ const exactLocator = page.getByRole(role as any, { name: gherkinRef, exact: true });
187
+ const exactCount = await exactLocator.count();
188
+ if (exactCount > 0) {
189
+ const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
190
+ if (await target.isVisible({ timeout: 3000 })) {
191
+ return {
192
+ locator: target,
193
+ selectorType: 'role',
194
+ selectorValue: role,
195
+ role: role,
196
+ matchMethod: 'exact_role',
197
+ warning: null,
198
+ };
199
+ }
200
+ }
201
+ } catch {
202
+ // Exact match not found, continue to regex
203
+ }
204
+
205
+ // Step 2: Regex fallback (substring match)
181
206
  try {
182
207
  const locator = page.getByRole(role as any, { name: namePattern });
183
208
  const count = await locator.count();
@@ -204,8 +229,30 @@ async function tryRole(
204
229
  return null;
205
230
  }
206
231
 
207
- // ④ getByLabel
208
- async function tryLabel(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
232
+ // ④ getByLabel — exact string first, then regex fallback
233
+ async function tryLabel(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
234
+ // Step 1: Exact string match
235
+ try {
236
+ const exactLocator = page.getByLabel(gherkinRef, { exact: true });
237
+ const exactCount = await exactLocator.count();
238
+ if (exactCount > 0) {
239
+ const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
240
+ if (await target.isVisible({ timeout: 3000 })) {
241
+ return {
242
+ locator: target,
243
+ selectorType: 'label',
244
+ selectorValue: '', // Will be filled from attrs
245
+ role: '',
246
+ matchMethod: 'label',
247
+ warning: null,
248
+ };
249
+ }
250
+ }
251
+ } catch {
252
+ // Exact match not found, continue to regex
253
+ }
254
+
255
+ // Step 2: Regex fallback
209
256
  try {
210
257
  const locator = page.getByLabel(namePattern);
211
258
  const count = await locator.count();
@@ -228,19 +275,42 @@ async function tryLabel(page: Page, namePattern: RegExp, nth: number): Promise<F
228
275
  return null;
229
276
  }
230
277
 
231
- // ⑤ getByPlaceholder
232
- async function tryPlaceholder(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
278
+ // ⑤ getByPlaceholder — exact string first, then regex fallback
279
+ async function tryPlaceholder(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
280
+ // Step 1: Exact string match
281
+ try {
282
+ const exactLocator = page.getByPlaceholder(gherkinRef, { exact: true });
283
+ const exactCount = await exactLocator.count();
284
+ if (exactCount > 0) {
285
+ const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
286
+ if (await target.isVisible({ timeout: 3000 })) {
287
+ const rawPlaceholder = await target.getAttribute('placeholder');
288
+ return {
289
+ locator: target,
290
+ selectorType: 'placeholder',
291
+ selectorValue: sanitizeText(rawPlaceholder || ''),
292
+ role: '',
293
+ matchMethod: 'placeholder',
294
+ warning: null,
295
+ };
296
+ }
297
+ }
298
+ } catch {
299
+ // Exact match not found, continue to regex
300
+ }
301
+
302
+ // Step 2: Regex fallback
233
303
  try {
234
304
  const locator = page.getByPlaceholder(namePattern);
235
305
  const count = await locator.count();
236
306
  if (count > 0) {
237
307
  const target = nth > 0 ? locator.nth(nth) : locator.first();
238
308
  if (await target.isVisible({ timeout: 3000 })) {
239
- const placeholder = await target.getAttribute('placeholder');
309
+ const rawPlaceholder = await target.getAttribute('placeholder');
240
310
  return {
241
311
  locator: target,
242
312
  selectorType: 'placeholder',
243
- selectorValue: placeholder || '',
313
+ selectorValue: sanitizeText(rawPlaceholder || ''),
244
314
  role: '',
245
315
  matchMethod: 'placeholder',
246
316
  warning: null,
@@ -253,8 +323,30 @@ async function tryPlaceholder(page: Page, namePattern: RegExp, nth: number): Pro
253
323
  return null;
254
324
  }
255
325
 
256
- // ⑥ getByText
257
- async function tryText(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
326
+ // ⑥ getByText — exact string first, then regex fallback
327
+ async function tryText(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
328
+ // Step 1: Exact string match
329
+ try {
330
+ const exactLocator = page.getByText(gherkinRef, { exact: true });
331
+ const exactCount = await exactLocator.count();
332
+ if (exactCount > 0) {
333
+ const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
334
+ if (await target.isVisible({ timeout: 3000 })) {
335
+ return {
336
+ locator: target,
337
+ selectorType: 'text',
338
+ selectorValue: '', // Will be filled from attrs
339
+ role: '',
340
+ matchMethod: 'text_only',
341
+ warning: null,
342
+ };
343
+ }
344
+ }
345
+ } catch {
346
+ // Exact match not found, continue to regex
347
+ }
348
+
349
+ // Step 2: Regex fallback
258
350
  try {
259
351
  const locator = page.getByText(namePattern);
260
352
  const count = await locator.count();
@@ -286,21 +378,25 @@ async function extractElementAttributes(locator: Locator): Promise<{
286
378
  }> {
287
379
  try {
288
380
  return await locator.evaluate((el) => {
381
+ // Inline sanitizer — browser context can't access Node functions
382
+ const clean = (s: string | null | undefined): string =>
383
+ (s || '').replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
384
+
289
385
  // Find associated label
290
386
  let label: string | null = null;
291
387
  if (el.id) {
292
388
  const labelEl = el.ownerDocument.querySelector(`label[for="${el.id}"]`);
293
- if (labelEl) label = labelEl.textContent?.trim() || null;
389
+ if (labelEl) label = clean(labelEl.textContent) || null;
294
390
  }
295
391
  if (!label && el.closest('label')) {
296
- label = el.closest('label')?.textContent?.trim() || null;
392
+ label = clean(el.closest('label')?.textContent) || null;
297
393
  }
298
394
 
299
395
  return {
300
396
  testid: el.getAttribute('data-testid'),
301
397
  tag: el.tagName.toLowerCase(),
302
- accessibleName: el.getAttribute('aria-label') || el.textContent?.trim()?.substring(0, 100) || '',
303
- placeholder: el.getAttribute('placeholder'),
398
+ accessibleName: clean(el.getAttribute('aria-label') || el.textContent?.trim()?.substring(0, 100)),
399
+ placeholder: clean(el.getAttribute('placeholder')) || null,
304
400
  label,
305
401
  };
306
402
  });
@@ -328,6 +424,31 @@ function buildUnresolvedElement(gherkinRef: string, gherkinType: string): LiveEl
328
424
  };
329
425
  }
330
426
 
427
+ /**
428
+ * Normalize a DOM text value for YAML output:
429
+ * collapse real newlines/tabs/carriage-returns into spaces, then deduplicate whitespace.
430
+ * Runs in both browser evaluate() and Node context.
431
+ */
432
+ function sanitizeText(str: string): string {
433
+ return str.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
434
+ }
435
+
436
+ /**
437
+ * Unescape a string extracted from Playwright's ariaSnapshot() output.
438
+ * ariaSnapshot encodes special chars as literal escape sequences:
439
+ * \n → newline, \t → tab, \\ → backslash, \" → quote
440
+ * We unescape them then normalize whitespace.
441
+ */
442
+ function unescapeAriaSnapshot(str: string): string {
443
+ return str
444
+ .replace(/\\n/g, ' ')
445
+ .replace(/\\t/g, ' ')
446
+ .replace(/\\"/g, '"')
447
+ .replace(/\\\\/g, '\\')
448
+ .replace(/\s+/g, ' ')
449
+ .trim();
450
+ }
451
+
331
452
  function escapeRegex(str: string): string {
332
453
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
333
454
  }
@@ -4,8 +4,7 @@
4
4
  * Merges elements across scenarios (first match wins).
5
5
  */
6
6
 
7
- import * as fs from 'fs';
8
- import * as yaml from 'yaml';
7
+ import { readYamlIfExists } from '../../utils/yaml-io';
9
8
  import { LiveElement, LiveScanResult } from './types';
10
9
 
11
10
  /**
@@ -13,12 +12,7 @@ import { LiveElement, LiveScanResult } from './types';
13
12
  * Returns null if file doesn't exist.
14
13
  */
15
14
  export function readMatrix(filePath: string): LiveScanResult | null {
16
- if (!fs.existsSync(filePath)) {
17
- return null;
18
- }
19
-
20
- const content = fs.readFileSync(filePath, 'utf-8');
21
- const parsed = yaml.parse(content);
15
+ const parsed = readYamlIfExists<any>(filePath);
22
16
 
23
17
  if (!parsed || !parsed.scenarios) {
24
18
  return null;
@@ -7,6 +7,16 @@ import * as fs from 'fs';
7
7
  import * as yaml from 'yaml';
8
8
  import { LiveScanResult } from './types';
9
9
 
10
+ /**
11
+ * Sanitize a string value before YAML serialization:
12
+ * collapse newlines/tabs/carriage-returns into spaces to prevent
13
+ * broken escape sequences (e.g. \\n) in QUOTE_DOUBLE output.
14
+ */
15
+ function sanitizeForYaml(value: string | null): string | null {
16
+ if (!value) return value;
17
+ return value.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim() || null;
18
+ }
19
+
10
20
  export function writeMatrix(result: LiveScanResult, outputPath: string): void {
11
21
  const output: any = {
12
22
  screen: result.screen,
@@ -31,13 +41,13 @@ export function writeMatrix(result: LiveScanResult, outputPath: string): void {
31
41
  scenarioData.elements[elementKey] = {
32
42
  gherkin_type: element.gherkinType,
33
43
  selector_type: element.selectorType,
34
- selector_value: element.selectorValue,
44
+ selector_value: sanitizeForYaml(element.selectorValue),
35
45
  role: element.role,
36
- name: element.name,
46
+ name: sanitizeForYaml(element.name),
37
47
  testid: element.testid,
38
48
  tag: element.tag,
39
- placeholder: element.placeholder,
40
- label: element.label,
49
+ placeholder: sanitizeForYaml(element.placeholder),
50
+ label: sanitizeForYaml(element.label),
41
51
  context: element.context,
42
52
  match_method: element.matchMethod,
43
53
  exact: element.exact,
@@ -100,6 +100,12 @@ export async function replaySteps(
100
100
  const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
101
101
  const nth = step.nth || 0;
102
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
+
103
109
  // Skip if element already resolved in existing scan (non-force mode)
104
110
  if (existingElements && existingElements[key] && existingElements[key].matchMethod !== 'unresolved') {
105
111
  elements[key] = existingElements[key];
@@ -279,6 +285,7 @@ function normalizeElementType(elementType: string, action: string): string {
279
285
  if (t === 'label') return 'label';
280
286
  if (t === 'uploader') return 'uploader';
281
287
  if (t === 'element') return 'element';
288
+ if (t === 'column' || t === 'columnheader') return 'column';
282
289
  if (t === 'logo' || t === 'image' || t === 'img' || t === 'icon') return 'img';
283
290
  if (t === 'dialog' || t === 'modal') return 'dialog';
284
291
  if (t === 'heading' || t === 'header') return 'heading';
@@ -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}}' });