@sun-asterisk/sungen 3.2.28 → 3.2.30

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 (486) hide show
  1. package/dist/capabilities/discover.d.ts +29 -0
  2. package/dist/capabilities/discover.d.ts.map +1 -1
  3. package/dist/capabilities/discover.js +144 -10
  4. package/dist/capabilities/discover.js.map +1 -1
  5. package/dist/capabilities/registry.d.ts +18 -0
  6. package/dist/capabilities/registry.d.ts.map +1 -1
  7. package/dist/capabilities/registry.js +25 -0
  8. package/dist/capabilities/registry.js.map +1 -1
  9. package/dist/cli/commands/audit.d.ts.map +1 -1
  10. package/dist/cli/commands/audit.js +9 -0
  11. package/dist/cli/commands/audit.js.map +1 -1
  12. package/dist/cli/commands/capability.js +1 -1
  13. package/dist/cli/commands/capability.js.map +1 -1
  14. package/dist/cli/commands/delivery.d.ts.map +1 -1
  15. package/dist/cli/commands/delivery.js +2 -1
  16. package/dist/cli/commands/delivery.js.map +1 -1
  17. package/dist/cli/commands/generate.d.ts.map +1 -1
  18. package/dist/cli/commands/generate.js +6 -2
  19. package/dist/cli/commands/generate.js.map +1 -1
  20. package/dist/cli/commands/inspect.js +1 -1
  21. package/dist/cli/commands/inspect.js.map +1 -1
  22. package/dist/cli/commands/results-merge.d.ts.map +1 -1
  23. package/dist/cli/commands/results-merge.js +9 -2
  24. package/dist/cli/commands/results-merge.js.map +1 -1
  25. package/dist/cli/commands/results-sanitize.d.ts +24 -0
  26. package/dist/cli/commands/results-sanitize.d.ts.map +1 -0
  27. package/dist/cli/commands/results-sanitize.js +126 -0
  28. package/dist/cli/commands/results-sanitize.js.map +1 -0
  29. package/dist/cli/commands/script-check.d.ts.map +1 -1
  30. package/dist/cli/commands/script-check.js +3 -1
  31. package/dist/cli/commands/script-check.js.map +1 -1
  32. package/dist/cli/commands/update.d.ts.map +1 -1
  33. package/dist/cli/commands/update.js +3 -0
  34. package/dist/cli/commands/update.js.map +1 -1
  35. package/dist/dashboard/templates/index.html +1 -1
  36. package/dist/exporters/api-testcase-formatter.d.ts +3 -6
  37. package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
  38. package/dist/exporters/api-testcase-formatter.js +7 -10
  39. package/dist/exporters/api-testcase-formatter.js.map +1 -1
  40. package/dist/exporters/feature-parser.d.ts +1 -1
  41. package/dist/exporters/feature-parser.js +1 -1
  42. package/dist/exporters/matrix/build.d.ts.map +1 -1
  43. package/dist/exporters/matrix/build.js +18 -3
  44. package/dist/exporters/matrix/build.js.map +1 -1
  45. package/dist/exporters/matrix/item-labels.d.ts +35 -0
  46. package/dist/exporters/matrix/item-labels.d.ts.map +1 -0
  47. package/dist/exporters/matrix/item-labels.js +90 -0
  48. package/dist/exporters/matrix/item-labels.js.map +1 -0
  49. package/dist/exporters/matrix/render-coverage-sheet.d.ts +14 -0
  50. package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -0
  51. package/dist/exporters/matrix/render-coverage-sheet.js +162 -0
  52. package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -0
  53. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  54. package/dist/exporters/matrix/render-csv.js +3 -1
  55. package/dist/exporters/matrix/render-csv.js.map +1 -1
  56. package/dist/exporters/matrix/render-overview-sheet.d.ts +20 -0
  57. package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -0
  58. package/dist/exporters/matrix/render-overview-sheet.js +32 -0
  59. package/dist/exporters/matrix/render-overview-sheet.js.map +1 -0
  60. package/dist/exporters/matrix/render-testcase-sheet.d.ts +30 -0
  61. package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -0
  62. package/dist/exporters/matrix/render-testcase-sheet.js +156 -0
  63. package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -0
  64. package/dist/exporters/matrix/render-xlsx.d.ts +41 -31
  65. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  66. package/dist/exporters/matrix/render-xlsx.js +72 -425
  67. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  68. package/dist/exporters/matrix/result-totals.d.ts +23 -0
  69. package/dist/exporters/matrix/result-totals.d.ts.map +1 -0
  70. package/dist/exporters/matrix/result-totals.js +21 -0
  71. package/dist/exporters/matrix/result-totals.js.map +1 -0
  72. package/dist/exporters/matrix/testcase-summary-band.d.ts +30 -0
  73. package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -0
  74. package/dist/exporters/matrix/testcase-summary-band.js +71 -0
  75. package/dist/exporters/matrix/testcase-summary-band.js.map +1 -0
  76. package/dist/exporters/matrix/wording.d.ts.map +1 -1
  77. package/dist/exporters/matrix/wording.js +13 -0
  78. package/dist/exporters/matrix/wording.js.map +1 -1
  79. package/dist/exporters/matrix/xlsx-cells.d.ts +38 -0
  80. package/dist/exporters/matrix/xlsx-cells.d.ts.map +1 -0
  81. package/dist/exporters/matrix/xlsx-cells.js +52 -0
  82. package/dist/exporters/matrix/xlsx-cells.js.map +1 -0
  83. package/dist/exporters/qa-env-secret-denylist.js +2 -2
  84. package/dist/exporters/qa-env-secret-denylist.js.map +1 -1
  85. package/dist/exporters/report-path-sanitizer.d.ts +38 -0
  86. package/dist/exporters/report-path-sanitizer.d.ts.map +1 -0
  87. package/dist/exporters/report-path-sanitizer.js +137 -0
  88. package/dist/exporters/report-path-sanitizer.js.map +1 -0
  89. package/dist/exporters/result-variants.d.ts.map +1 -1
  90. package/dist/exporters/result-variants.js +2 -1
  91. package/dist/exporters/result-variants.js.map +1 -1
  92. package/dist/exporters/sensitive-key.d.ts +31 -0
  93. package/dist/exporters/sensitive-key.d.ts.map +1 -0
  94. package/dist/exporters/sensitive-key.js +50 -0
  95. package/dist/exporters/sensitive-key.js.map +1 -0
  96. package/dist/exporters/test-data-resolver.d.ts +4 -1
  97. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  98. package/dist/exporters/test-data-resolver.js +12 -2
  99. package/dist/exporters/test-data-resolver.js.map +1 -1
  100. package/dist/exporters/xlsx-report-builder.d.ts +12 -1
  101. package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
  102. package/dist/exporters/xlsx-report-builder.js +10 -2
  103. package/dist/exporters/xlsx-report-builder.js.map +1 -1
  104. package/dist/generators/gherkin-parser/index.d.ts +10 -0
  105. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  106. package/dist/generators/gherkin-parser/index.js +20 -12
  107. package/dist/generators/gherkin-parser/index.js.map +1 -1
  108. package/dist/generators/gherkin-parser/parent-scope-clause.d.ts +54 -0
  109. package/dist/generators/gherkin-parser/parent-scope-clause.d.ts.map +1 -0
  110. package/dist/generators/gherkin-parser/parent-scope-clause.js +109 -0
  111. package/dist/generators/gherkin-parser/parent-scope-clause.js.map +1 -0
  112. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +23 -18
  113. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  114. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +4 -19
  115. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
  116. package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
  117. package/dist/generators/test-generator/adapters/appium/os-support.d.ts +53 -0
  118. package/dist/generators/test-generator/adapters/appium/os-support.d.ts.map +1 -0
  119. package/dist/generators/test-generator/adapters/appium/os-support.js +200 -0
  120. package/dist/generators/test-generator/adapters/appium/os-support.js.map +1 -0
  121. package/dist/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
  122. package/dist/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
  123. package/dist/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
  124. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
  125. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
  126. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
  127. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
  128. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
  129. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
  130. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
  131. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
  132. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
  133. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
  134. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
  135. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
  136. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
  137. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
  138. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
  139. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
  140. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
  141. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
  142. package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
  143. package/dist/generators/test-generator/adapters/index.d.ts +1 -1
  144. package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
  145. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +4 -19
  146. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  147. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  148. package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
  149. package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
  150. package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
  151. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  152. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
  153. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
  154. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
  155. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
  156. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
  157. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
  158. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
  159. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
  160. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
  161. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
  162. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
  163. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
  164. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
  165. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
  166. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
  167. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
  168. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
  169. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
  170. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
  171. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
  172. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  173. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
  174. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
  175. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
  176. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
  177. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
  178. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
  179. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
  180. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
  181. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
  182. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
  183. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
  184. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
  185. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
  186. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
  187. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
  188. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
  189. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
  190. package/dist/generators/test-generator/code-generator.d.ts +37 -0
  191. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  192. package/dist/generators/test-generator/code-generator.js +165 -40
  193. package/dist/generators/test-generator/code-generator.js.map +1 -1
  194. package/dist/generators/test-generator/diagnostics.d.ts +116 -6
  195. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  196. package/dist/generators/test-generator/diagnostics.js +115 -5
  197. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  198. package/dist/generators/test-generator/patterns/index.d.ts +57 -11
  199. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  200. package/dist/generators/test-generator/patterns/index.js +163 -21
  201. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  202. package/dist/generators/test-generator/patterns/types.d.ts +8 -0
  203. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  204. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +18 -0
  205. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -0
  206. package/dist/generators/test-generator/patterns/with-parent-scope.js +40 -0
  207. package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -0
  208. package/dist/generators/test-generator/step-mapper.d.ts +103 -10
  209. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  210. package/dist/generators/test-generator/step-mapper.js +266 -45
  211. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  212. package/dist/generators/test-generator/template-engine.d.ts +4 -19
  213. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  214. package/dist/generators/test-generator/template-engine.js +17 -12
  215. package/dist/generators/test-generator/template-engine.js.map +1 -1
  216. package/dist/generators/test-generator/utils/data-resolver.d.ts +7 -0
  217. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  218. package/dist/generators/test-generator/utils/data-resolver.js +19 -2
  219. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  220. package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts +41 -0
  221. package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts.map +1 -0
  222. package/dist/generators/test-generator/utils/dialog-scope-identity.js +61 -0
  223. package/dist/generators/test-generator/utils/dialog-scope-identity.js.map +1 -0
  224. package/dist/generators/test-generator/utils/escape-js-string.d.ts +17 -0
  225. package/dist/generators/test-generator/utils/escape-js-string.d.ts.map +1 -0
  226. package/dist/generators/test-generator/utils/escape-js-string.js +29 -0
  227. package/dist/generators/test-generator/utils/escape-js-string.js.map +1 -0
  228. package/dist/generators/test-generator/utils/nearest-match.d.ts +24 -0
  229. package/dist/generators/test-generator/utils/nearest-match.d.ts.map +1 -0
  230. package/dist/generators/test-generator/utils/nearest-match.js +56 -0
  231. package/dist/generators/test-generator/utils/nearest-match.js.map +1 -0
  232. package/dist/generators/test-generator/utils/selector-entry-fields.d.ts +58 -0
  233. package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -0
  234. package/dist/generators/test-generator/utils/selector-entry-fields.js +119 -0
  235. package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -0
  236. package/dist/generators/test-generator/utils/selector-entry-walk.d.ts +25 -0
  237. package/dist/generators/test-generator/utils/selector-entry-walk.d.ts.map +1 -0
  238. package/dist/generators/test-generator/utils/selector-entry-walk.js +54 -0
  239. package/dist/generators/test-generator/utils/selector-entry-walk.js.map +1 -0
  240. package/dist/generators/test-generator/utils/selector-nth-validation.d.ts +59 -0
  241. package/dist/generators/test-generator/utils/selector-nth-validation.d.ts.map +1 -0
  242. package/dist/generators/test-generator/utils/selector-nth-validation.js +91 -0
  243. package/dist/generators/test-generator/utils/selector-nth-validation.js.map +1 -0
  244. package/dist/generators/test-generator/utils/selector-resolver.d.ts +53 -2
  245. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  246. package/dist/generators/test-generator/utils/selector-resolver.js +273 -27
  247. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  248. package/dist/generators/test-generator/utils/selector-type-validation.d.ts +51 -0
  249. package/dist/generators/test-generator/utils/selector-type-validation.d.ts.map +1 -0
  250. package/dist/generators/test-generator/utils/selector-type-validation.js +77 -0
  251. package/dist/generators/test-generator/utils/selector-type-validation.js.map +1 -0
  252. package/dist/harness/audit.d.ts +3 -1
  253. package/dist/harness/audit.d.ts.map +1 -1
  254. package/dist/harness/audit.js +51 -28
  255. package/dist/harness/audit.js.map +1 -1
  256. package/dist/harness/capability-plan.d.ts +4 -0
  257. package/dist/harness/capability-plan.d.ts.map +1 -1
  258. package/dist/harness/capability-plan.js +32 -2
  259. package/dist/harness/capability-plan.js.map +1 -1
  260. package/dist/harness/catalog/drivers.yaml +1 -1
  261. package/dist/harness/catalog/universal-viewpoints.yaml +145 -0
  262. package/dist/harness/data-driven-lint.d.ts.map +1 -1
  263. package/dist/harness/data-driven-lint.js +217 -33
  264. package/dist/harness/data-driven-lint.js.map +1 -1
  265. package/dist/harness/parse.d.ts +6 -0
  266. package/dist/harness/parse.d.ts.map +1 -1
  267. package/dist/harness/parse.js +1 -1
  268. package/dist/harness/parse.js.map +1 -1
  269. package/dist/harness/repair.d.ts.map +1 -1
  270. package/dist/harness/repair.js +8 -1
  271. package/dist/harness/repair.js.map +1 -1
  272. package/dist/harness/script-check.d.ts +2 -2
  273. package/dist/harness/script-check.d.ts.map +1 -1
  274. package/dist/harness/script-check.js +186 -25
  275. package/dist/harness/script-check.js.map +1 -1
  276. package/dist/harness/sensors.d.ts +48 -0
  277. package/dist/harness/sensors.d.ts.map +1 -1
  278. package/dist/harness/sensors.js +26 -1
  279. package/dist/harness/sensors.js.map +1 -1
  280. package/dist/harness/viewpoint-ledger.d.ts +10 -0
  281. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  282. package/dist/harness/viewpoint-ledger.js +23 -2
  283. package/dist/harness/viewpoint-ledger.js.map +1 -1
  284. package/dist/index.d.ts +2 -0
  285. package/dist/index.d.ts.map +1 -1
  286. package/dist/index.js +10 -1
  287. package/dist/index.js.map +1 -1
  288. package/dist/orchestrator/project-initializer.d.ts +6 -0
  289. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  290. package/dist/orchestrator/project-initializer.js +16 -0
  291. package/dist/orchestrator/project-initializer.js.map +1 -1
  292. package/dist/orchestrator/report-sanitize-reporter-install.d.ts +24 -0
  293. package/dist/orchestrator/report-sanitize-reporter-install.d.ts.map +1 -0
  294. package/dist/orchestrator/report-sanitize-reporter-install.js +161 -0
  295. package/dist/orchestrator/report-sanitize-reporter-install.js.map +1 -0
  296. package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -3
  297. package/dist/orchestrator/templates/ai-src/commands/run-test.md +9 -1
  298. package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
  299. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
  300. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
  301. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
  302. package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
  303. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
  304. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
  305. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
  306. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
  307. package/dist/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
  308. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
  309. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
  310. package/dist/orchestrator/templates/playwright.config.ts +7 -0
  311. package/dist/orchestrator/templates/readme.md +1 -1
  312. package/dist/orchestrator/templates/specs-checked-state.d.ts +83 -0
  313. package/dist/orchestrator/templates/specs-checked-state.d.ts.map +1 -0
  314. package/dist/orchestrator/templates/specs-checked-state.js +261 -0
  315. package/dist/orchestrator/templates/specs-checked-state.js.map +1 -0
  316. package/dist/orchestrator/templates/specs-checked-state.ts +324 -0
  317. package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  318. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts +36 -0
  319. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts.map +1 -0
  320. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js +155 -0
  321. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js.map +1 -0
  322. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
  323. package/dist/orchestrator/templates/specs-url-assert.d.ts +50 -25
  324. package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
  325. package/dist/orchestrator/templates/specs-url-assert.js +65 -24
  326. package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
  327. package/dist/orchestrator/templates/specs-url-assert.ts +101 -28
  328. package/dist/orchestrator/templates/wdio.conf.ts +105 -1
  329. package/dist/utils/selector-types.d.ts +43 -1
  330. package/dist/utils/selector-types.d.ts.map +1 -1
  331. package/dist/utils/selector-types.js +51 -7
  332. package/dist/utils/selector-types.js.map +1 -1
  333. package/package.json +3 -3
  334. package/src/capabilities/discover.ts +146 -10
  335. package/src/capabilities/registry.ts +30 -0
  336. package/src/cli/commands/audit.ts +9 -0
  337. package/src/cli/commands/capability.ts +1 -1
  338. package/src/cli/commands/delivery.ts +2 -1
  339. package/src/cli/commands/generate.ts +5 -2
  340. package/src/cli/commands/inspect.ts +1 -1
  341. package/src/cli/commands/results-merge.ts +9 -2
  342. package/src/cli/commands/results-sanitize.ts +98 -0
  343. package/src/cli/commands/script-check.ts +3 -1
  344. package/src/cli/commands/update.ts +3 -0
  345. package/src/dashboard/templates/index.html +1 -1
  346. package/src/exporters/api-testcase-formatter.ts +5 -7
  347. package/src/exporters/feature-parser.ts +1 -1
  348. package/src/exporters/matrix/build.ts +17 -3
  349. package/src/exporters/matrix/item-labels.ts +78 -0
  350. package/src/exporters/matrix/render-coverage-sheet.ts +170 -0
  351. package/src/exporters/matrix/render-csv.ts +3 -1
  352. package/src/exporters/matrix/render-overview-sheet.ts +51 -0
  353. package/src/exporters/matrix/render-testcase-sheet.ts +178 -0
  354. package/src/exporters/matrix/render-xlsx.ts +67 -448
  355. package/src/exporters/matrix/result-totals.ts +37 -0
  356. package/src/exporters/matrix/testcase-summary-band.ts +74 -0
  357. package/src/exporters/matrix/wording.ts +13 -0
  358. package/src/exporters/matrix/xlsx-cells.ts +56 -0
  359. package/src/exporters/qa-env-secret-denylist.ts +1 -1
  360. package/src/exporters/report-path-sanitizer.ts +144 -0
  361. package/src/exporters/result-variants.ts +2 -1
  362. package/src/exporters/sensitive-key.ts +48 -0
  363. package/src/exporters/test-data-resolver.ts +12 -2
  364. package/src/exporters/xlsx-report-builder.ts +16 -2
  365. package/src/generators/gherkin-parser/index.ts +22 -11
  366. package/src/generators/gherkin-parser/parent-scope-clause.ts +130 -0
  367. package/src/generators/test-generator/adapters/adapter-interface.ts +25 -3
  368. package/src/generators/test-generator/adapters/appium/appium-adapter.ts +4 -4
  369. package/src/generators/test-generator/adapters/appium/os-support.ts +176 -0
  370. package/src/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
  371. package/src/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
  372. package/src/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
  373. package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
  374. package/src/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
  375. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
  376. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
  377. package/src/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
  378. package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
  379. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
  380. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
  381. package/src/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
  382. package/src/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
  383. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
  384. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
  385. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
  386. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
  387. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
  388. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
  389. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
  390. package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
  391. package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
  392. package/src/generators/test-generator/adapters/index.ts +1 -1
  393. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +4 -4
  394. package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
  395. package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
  396. package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
  397. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  398. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
  399. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
  400. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
  401. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
  402. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
  403. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
  404. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
  405. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
  406. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
  407. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
  408. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
  409. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
  410. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
  411. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
  412. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
  413. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
  414. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
  415. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
  416. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
  417. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
  418. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  419. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
  420. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
  421. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
  422. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
  423. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
  424. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
  425. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
  426. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
  427. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
  428. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
  429. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
  430. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
  431. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
  432. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
  433. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
  434. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
  435. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
  436. package/src/generators/test-generator/code-generator.ts +181 -46
  437. package/src/generators/test-generator/diagnostics.ts +117 -6
  438. package/src/generators/test-generator/patterns/index.ts +175 -24
  439. package/src/generators/test-generator/patterns/types.ts +8 -0
  440. package/src/generators/test-generator/patterns/with-parent-scope.ts +41 -0
  441. package/src/generators/test-generator/step-mapper.ts +277 -43
  442. package/src/generators/test-generator/template-engine.ts +21 -21
  443. package/src/generators/test-generator/utils/data-resolver.ts +23 -2
  444. package/src/generators/test-generator/utils/dialog-scope-identity.ts +71 -0
  445. package/src/generators/test-generator/utils/escape-js-string.ts +24 -0
  446. package/src/generators/test-generator/utils/nearest-match.ts +55 -0
  447. package/src/generators/test-generator/utils/selector-entry-fields.ts +131 -0
  448. package/src/generators/test-generator/utils/selector-entry-walk.ts +58 -0
  449. package/src/generators/test-generator/utils/selector-nth-validation.ts +99 -0
  450. package/src/generators/test-generator/utils/selector-resolver.ts +333 -28
  451. package/src/generators/test-generator/utils/selector-type-validation.ts +87 -0
  452. package/src/harness/audit.ts +55 -30
  453. package/src/harness/capability-plan.ts +33 -1
  454. package/src/harness/catalog/drivers.yaml +1 -1
  455. package/src/harness/catalog/universal-viewpoints.yaml +145 -0
  456. package/src/harness/data-driven-lint.ts +192 -32
  457. package/src/harness/parse.ts +7 -1
  458. package/src/harness/repair.ts +8 -1
  459. package/src/harness/script-check.ts +186 -21
  460. package/src/harness/sensors.ts +75 -1
  461. package/src/harness/viewpoint-ledger.ts +26 -5
  462. package/src/index.ts +7 -0
  463. package/src/orchestrator/project-initializer.ts +17 -0
  464. package/src/orchestrator/report-sanitize-reporter-install.ts +109 -0
  465. package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -3
  466. package/src/orchestrator/templates/ai-src/commands/run-test.md +9 -1
  467. package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
  468. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
  469. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
  470. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
  471. package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
  472. package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
  473. package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
  474. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
  475. package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
  476. package/src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
  477. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
  478. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
  479. package/src/orchestrator/templates/playwright.config.ts +7 -0
  480. package/src/orchestrator/templates/readme.md +1 -1
  481. package/src/orchestrator/templates/specs-checked-state.ts +324 -0
  482. package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  483. package/src/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
  484. package/src/orchestrator/templates/specs-url-assert.ts +101 -28
  485. package/src/orchestrator/templates/wdio.conf.ts +105 -1
  486. package/src/utils/selector-types.ts +54 -5
@@ -2,7 +2,8 @@
2
2
  /**
3
3
  * Sungen URL assertion helper — auto-generated into specs/url-assert.ts. DO NOT EDIT.
4
4
  *
5
- * Every Then-side URL assertion (`see [X] page`, `is on [X] page`) compiles to one call here.
5
+ * Every URL step compiles to one call here: the Then-side assertions (`see [X] page`,
6
+ * `is on [X] page`) to `expectPage`, and `wait for [X] page` to `waitForPage`.
6
7
  *
7
8
  * Why a helper and not an inline predicate. The predicate used to be emitted inline into every
8
9
  * spec, so each correction to what "the URL matches" MEANS was a breaking change for every
@@ -28,6 +29,16 @@ export interface UrlExpectation {
28
29
  * against a full URL.
29
30
  */
30
31
  pathname: RegExp;
32
+ /**
33
+ * Anchored hostname pattern, emitted ONLY when the page selector's `value` is an ABSOLUTE URL
34
+ * (`https://app.example.com/reception/:id`) — a destination on a different host from the suite's
35
+ * baseURL. Absent means "whatever host we are on", which is what a relative page value says.
36
+ *
37
+ * It is a SEPARATE field rather than part of `pathname` because the two are read off different
38
+ * properties of the parsed URL: `u.hostname` never appears in `u.pathname`. One concatenated
39
+ * regex only worked while the match ran unanchored over the whole URL string (#677).
40
+ */
41
+ hostname?: RegExp;
31
42
  /**
32
43
  * The `with {{v}}` value, raw from test-data: '?q=1' · '/vi/search?q=1' · '#tab' · ''.
33
44
  * `undefined` means the step declared nothing, which is itself an assertion — see below.
@@ -83,6 +94,15 @@ function decodedPath(pathname: string): string {
83
94
  }
84
95
  }
85
96
 
97
+ /**
98
+ * Is the URL at the expected LOCATION — right host, right path? The half every URL step shares.
99
+ * The Then-side assertion goes on to judge the query; the wait stops here (see `waitForPage`).
100
+ */
101
+ function locationMatches(pathname: RegExp, hostname: RegExp | undefined, u: URL): boolean {
102
+ if (hostname && !hostname.test(u.hostname)) return false;
103
+ return pathname.test(u.pathname) || pathname.test(decodedPath(u.pathname));
104
+ }
105
+
86
106
  /**
87
107
  * Build the predicate for `expect(page).toHaveURL(...)`.
88
108
  *
@@ -94,9 +114,9 @@ function decodedPath(pathname: string): string {
94
114
  * A declared fragment is asserted too; a declared value carrying no query
95
115
  * at all constrains the path only (the compiler warns: SG-W014).
96
116
  */
97
- export function urlMatches({ pathname, declared, dataRef }: UrlExpectation): (u: URL) => boolean {
117
+ export function urlMatches({ pathname, hostname, declared, dataRef }: UrlExpectation): (u: URL) => boolean {
98
118
  return (u: URL): boolean => {
99
- if (!pathname.test(u.pathname) && !pathname.test(decodedPath(u.pathname))) return false;
119
+ if (!locationMatches(pathname, hostname, u)) return false;
100
120
 
101
121
  // `dataRef`, not `declared`, decides which rule applies. Both "the step declared nothing" and
102
122
  // "the step declared {{v}} but the key resolved to nothing at runtime" arrive here as
@@ -135,38 +155,43 @@ export function urlMatches({ pathname, declared, dataRef }: UrlExpectation): (u:
135
155
  };
136
156
  }
137
157
 
158
+ /** What `settleAndHold` needs of a page — Playwright's `Page` satisfies it; so does a test fake. */
159
+ type SettleablePage = {
160
+ url(): string;
161
+ waitForLoadState(state: 'networkidle', opts?: { timeout?: number }): Promise<void>;
162
+ };
163
+
164
+ /** The two runtime knobs, shared by both URL steps. */
165
+ interface SettleOpts { settleMs?: number; networkIdleMs?: number }
166
+
138
167
  /**
139
- * `toHaveURL` is a polling assertion: it passes on the FIRST sample that matches. A client-side
140
- * router pushes the destination URL before the route guard or the API has answered, so a user
141
- * with no permission is "on" `/items/detail` for a few hundred milliseconds — long enough for
142
- * the assertion to sample it, pass, and end the test green — and is then bounced to `/forbidden`
143
- * with no assertion left to see it. A real project shipped a permission matrix on that oracle;
144
- * the 403s were found by hand (#662).
168
+ * A URL that MATCHES is not a page the user is still on. A client-side router pushes the
169
+ * destination URL before the route guard or the API has answered, so a user with no permission is
170
+ * "on" `/items/detail` for a few hundred milliseconds — long enough for a polling assertion to
171
+ * sample it and pass, or for a `waitForURL` to resolve — and is then bounced to `/forbidden` with
172
+ * nothing left watching. A real project shipped a permission matrix on that oracle; the 403s were
173
+ * found by hand (#662).
145
174
  *
146
- * `expectPage` is the page oracle `see [X] page` compiles to now. Arriving is not enough: the URL
147
- * has to be STILL matching once the page has settled.
148
- * 1. arrive — the same predicate `toHaveURL` always used;
149
- * 2. settle — wait for network to go quiet (bounded: an app that polls forever must not hang
150
- * the test, so a timeout here is not a failure);
151
- * 3. hold — sample the URL over a settle window; the moment it stops matching, fail and
152
- * NAME where it went, because that destination is the finding;
153
- * 4. re-assert — the arrival predicate, once more, on the settled page.
175
+ * So both URL steps go through this: having arrived,
176
+ * 1. settle — wait for network to go quiet (bounded: an app that polls forever must not hang
177
+ * the test, so a timeout here is not a failure);
178
+ * 2. hold — sample the URL over a settle window; the moment it stops matching, fail and
179
+ * NAME where it went, because that destination is the finding.
180
+ * The caller decides what arriving meant and what to do afterwards.
154
181
  *
155
182
  * `SUNGEN_URL_SETTLE_MS` (default 1000) is the hold window; `SUNGEN_URL_NETWORKIDLE_MS` (default
156
- * 3000) bounds step 2. Both are runtime knobs, so a slow environment is a config change, not a
183
+ * 3000) bounds step 1. Both are runtime knobs, so a slow environment is a config change, not a
157
184
  * regenerate.
158
185
  */
159
- export async function expectPage(
160
- page: { url(): string; waitForLoadState(state: 'networkidle', opts?: { timeout?: number }): Promise<void> },
161
- expectation: UrlExpectation,
162
- opts: { settleMs?: number; networkIdleMs?: number; assertUrl?: (matches: (u: URL) => boolean) => Promise<void> } = {},
186
+ async function settleAndHold(
187
+ page: SettleablePage,
188
+ matches: (u: URL) => boolean,
189
+ opts: SettleOpts,
190
+ label: string,
191
+ consequence: string,
163
192
  ): Promise<void> {
164
193
  const settleMs = opts.settleMs ?? Number(process.env.SUNGEN_URL_SETTLE_MS ?? 1000);
165
194
  const networkIdleMs = opts.networkIdleMs ?? Number(process.env.SUNGEN_URL_NETWORKIDLE_MS ?? 3000);
166
- const matches = urlMatches(expectation);
167
- const assertUrl = opts.assertUrl ?? (async (m: (u: URL) => boolean) => { await expect(page as unknown as Page).toHaveURL(m); });
168
-
169
- await assertUrl(matches);
170
195
  const arrivedAt = page.url();
171
196
 
172
197
  await page.waitForLoadState('networkidle', { timeout: networkIdleMs }).catch(() => undefined);
@@ -176,13 +201,61 @@ export async function expectPage(
176
201
  const now = page.url();
177
202
  if (!matches(new URL(now))) {
178
203
  throw new Error(
179
- `page assertion: reached ${arrivedAt} and then left for ${now} after ${Date.now() - started}ms — `
204
+ `${label}: reached ${arrivedAt} and then left for ${now} after ${Date.now() - started}ms — `
180
205
  + 'a route guard, an error boundary or a redirect moved the user away after the URL had already '
181
- + 'matched. The page the test asserted is not the page the user ended on.',
206
+ + `matched. ${consequence}`,
182
207
  );
183
208
  }
184
209
  await new Promise((r) => setTimeout(r, 50));
185
210
  }
211
+ }
212
+
213
+ /**
214
+ * `expectPage` is the page oracle `see [X] page` / `is on [X] page` compile to. Arriving is not
215
+ * enough: the URL has to be STILL matching once the page has settled.
216
+ * 1. arrive — the same predicate `toHaveURL` always used;
217
+ * 2. settle + hold — see `settleAndHold`;
218
+ * 3. re-assert — the arrival predicate, once more, on the settled page.
219
+ */
220
+ export async function expectPage(
221
+ page: SettleablePage,
222
+ expectation: UrlExpectation,
223
+ opts: SettleOpts & { assertUrl?: (matches: (u: URL) => boolean) => Promise<void> } = {},
224
+ ): Promise<void> {
225
+ const matches = urlMatches(expectation);
226
+ const assertUrl = opts.assertUrl ?? (async (m: (u: URL) => boolean) => { await expect(page as unknown as Page).toHaveURL(m); });
186
227
 
187
228
  await assertUrl(matches);
229
+ await settleAndHold(page, matches, opts, 'page assertion',
230
+ 'The page the test asserted is not the page the user ended on.');
231
+ await assertUrl(matches);
232
+ }
233
+
234
+ /**
235
+ * `waitForPage` is what `When User wait for [X] page` compiles to (#677).
236
+ *
237
+ * A bare `page.waitForURL(/…/)` resolves on the first URL sample that matches — the transient URL
238
+ * the router pushed before its guard decided. The wait then returned, and every step AFTER it ran
239
+ * against a page mid-redirect, so their failures pointed at the wrong thing. It was also the third
240
+ * hand-rolled copy of "does this URL match", drifting from the pair #662 consolidated here.
241
+ *
242
+ * Where this deliberately DIFFERS from `expectPage`: the query is not constrained. A Then-side page
243
+ * assertion is an oracle, so a bare page must be bare — `/vi/search` fails on `/vi/search?x=1`. A
244
+ * wait is not an oracle: `wait for [Results] page` after submitting a search legitimately lands on
245
+ * `/results?q=abc`, and reddening there would assert something the step never said. Prove the query
246
+ * with the `Then User see [Results] page with {{v}}` that follows.
247
+ */
248
+ export async function waitForPage(
249
+ page: SettleablePage & { waitForURL(url: (u: URL) => boolean, opts?: { timeout?: number }): Promise<void> },
250
+ expectation: UrlExpectation,
251
+ opts: SettleOpts & { timeout?: number; waitUrl?: (matches: (u: URL) => boolean) => Promise<void> } = {},
252
+ ): Promise<void> {
253
+ const { pathname, hostname } = expectation;
254
+ const matches = (u: URL): boolean => locationMatches(pathname, hostname, u);
255
+ // Playwright's own navigation timeout governs the arrival; only the hold is sungen's.
256
+ const arrive = opts.waitUrl ?? (async (m: (u: URL) => boolean) => { await page.waitForURL(m, { timeout: opts.timeout }); });
257
+
258
+ await arrive(matches);
259
+ await settleAndHold(page, matches, opts, 'page wait',
260
+ 'The steps after this wait would have run against a page the user is already being moved off.');
188
261
  }
@@ -28,6 +28,26 @@ import * as path from 'node:path';
28
28
  import { execSync } from 'node:child_process';
29
29
  import PwShapeReporter from './specs/reporters/pw-shape-reporter';
30
30
 
31
+ /**
32
+ * Failure-evidence output. `test-results/` is already gitignored — screenshots and page sources
33
+ * of a real app routinely contain live data (a signed-in email, a token rendered on screen), so
34
+ * this directory must never become committable.
35
+ */
36
+ const EVIDENCE_ROOT = path.join('test-results', 'mobile');
37
+ /** A full logcat is unbounded; only the tail is ever diagnostic. */
38
+ const EVIDENCE_LOG_TAIL_LINES = 500;
39
+ /** ~2 MB of accessibility tree is already far more than anyone reads. */
40
+ const EVIDENCE_PAGE_SOURCE_MAX = 2_000_000;
41
+
42
+ /** Filesystem-safe path segment from a feature/test title. */
43
+ function evidenceSlug(s: string): string {
44
+ return String(s)
45
+ .toLowerCase()
46
+ .replace(/[^a-z0-9]+/g, '-')
47
+ .replace(/^-+|-+$/g, '')
48
+ .slice(0, 80) || 'unnamed';
49
+ }
50
+
31
51
  /**
32
52
  * Auto-select MOBILE specs and classify each by its target OS (dual-target routing).
33
53
  *
@@ -404,9 +424,93 @@ export const config: WebdriverIO.Config = {
404
424
  // Connectivity self-heal (#615): onPrepare heals a device wedged by a previous KILLED run
405
425
  // (its onComplete never fired) before the session starts; onComplete restores after this run,
406
426
  // pass or fail. Both run in the launcher process, so they fire even when the worker/session died.
407
- onPrepare: () => { restoreConnectivity('onPrepare'); setShowTouches('onPrepare'); },
427
+ onPrepare: () => { restoreConnectivity('onPrepare'); setShowTouches('onPrepare'); fs.mkdirSync(EVIDENCE_ROOT, { recursive: true }); },
408
428
  onComplete: () => { restoreConnectivity('onComplete'); setShowTouches('onComplete'); },
409
429
 
430
+ /**
431
+ * Failure evidence. A mobile failure used to reach the report as a single error string — no
432
+ * image, no tree, no device log — which makes triaging a native UI almost impossible.
433
+ *
434
+ * Only runs on failure, so a passing suite pays nothing. Each capture is wrapped SEPARATELY:
435
+ * one unavailable command (a Flutter page source that blows the buffer, a driver with no log
436
+ * endpoint) must not cost us the other two, and nothing in here may convert an already-failing
437
+ * test into a different error.
438
+ */
439
+ afterTest: async (
440
+ test: { title?: string; parent?: string },
441
+ _context: unknown,
442
+ result: { passed?: boolean },
443
+ ): Promise<void> => {
444
+ if (result?.passed) return;
445
+
446
+ // Opt-out for constrained runners (a device farm billing per artifact, a CI box with no disk).
447
+ // A feature tagged @screenshot:on-failure declares its evidence essential and overrides it.
448
+ const forced = (globalThis as Record<string, unknown>).__sungenForceEvidence === true;
449
+ if (!forced && process.env.SUNGEN_MOBILE_EVIDENCE === 'off') return;
450
+
451
+ const feature = test?.parent || 'Tests';
452
+ const title = test?.title || 'test';
453
+ const dir = path.join(EVIDENCE_ROOT, evidenceSlug(feature), evidenceSlug(title));
454
+ const files: Array<{ name: string; path: string; contentType: string }> = [];
455
+
456
+ try {
457
+ fs.mkdirSync(dir, { recursive: true });
458
+ } catch (e) {
459
+ console.warn(`[sungen] could not create evidence dir ${dir}: ${(e as Error).message}`);
460
+ return;
461
+ }
462
+
463
+ // 1. Screenshot — the single most useful artifact for a UI failure.
464
+ try {
465
+ const shot = path.join(dir, 'screenshot.png');
466
+ await driver.saveScreenshot(shot);
467
+ files.push({ name: 'screenshot', path: shot, contentType: 'image/png' });
468
+ } catch (e) {
469
+ console.warn(`[sungen] screenshot capture failed: ${(e as Error).message}`);
470
+ }
471
+
472
+ // 2. Page source — the accessibility tree, i.e. WHY a selector did not match. Capped: a
473
+ // Flutter/RecyclerView tree can run to tens of MB and there is no value in writing that.
474
+ try {
475
+ const src = await driver.getPageSource();
476
+ const capped = src.length > EVIDENCE_PAGE_SOURCE_MAX
477
+ ? `${src.slice(0, EVIDENCE_PAGE_SOURCE_MAX)}\n<!-- [sungen] truncated at ${EVIDENCE_PAGE_SOURCE_MAX} of ${src.length} chars -->`
478
+ : src;
479
+ if (src.length > EVIDENCE_PAGE_SOURCE_MAX) {
480
+ console.warn(`[sungen] page source ${src.length} chars — truncated to ${EVIDENCE_PAGE_SOURCE_MAX}`);
481
+ }
482
+ const out = path.join(dir, 'page-source.xml');
483
+ fs.writeFileSync(out, capped, 'utf-8');
484
+ files.push({ name: 'page-source', path: out, contentType: 'application/xml' });
485
+ } catch (e) {
486
+ console.warn(`[sungen] page source capture failed: ${(e as Error).message}`);
487
+ }
488
+
489
+ // 3. Device log — logcat on Android, syslog on iOS. Tail only: a full logcat is unbounded.
490
+ try {
491
+ const logType = driver.isIOS ? 'syslog' : 'logcat';
492
+ const entries = (await driver.getLogs(logType)) as Array<{ message?: string } | string>;
493
+ const lines = entries.map((l) => (typeof l === 'string' ? l : l?.message || '')).filter(Boolean);
494
+ const tail = lines.slice(-EVIDENCE_LOG_TAIL_LINES).join('\n');
495
+ const out = path.join(dir, 'device.log');
496
+ fs.writeFileSync(out, tail, 'utf-8');
497
+ files.push({ name: 'device-log', path: out, contentType: 'text/plain' });
498
+ } catch (e) {
499
+ console.warn(`[sungen] device log capture failed: ${(e as Error).message}`);
500
+ }
501
+
502
+ // Hand the paths to the reporter so they land in the result's `attachments`. Resolved off
503
+ // globalThis, not imported — see the note in specs/reporters/pw-shape-reporter.ts.
504
+ try {
505
+ const attach = (globalThis as Record<string, unknown>).__sungenAttachEvidence;
506
+ if (typeof attach === 'function') {
507
+ (attach as (f: string, t: string, files: typeof files) => void)(feature, title, files);
508
+ }
509
+ } catch (e) {
510
+ console.warn(`[sungen] could not register evidence with the reporter: ${(e as Error).message}`);
511
+ }
512
+ },
513
+
410
514
  // iOS + locale: XCUITest's `noReset:false` does NOT actually clear the app's data container
411
515
  // (verified live 2026-06-11) — a Flutter app that persisted its language on a previous launch keeps
412
516
  // it and ignores the new device locale, so the i18n run asserts the wrong language. Wipe the app
@@ -1,7 +1,49 @@
1
1
  /**
2
2
  * Valid selector types used across scaffold generator, selector resolver, and validator.
3
3
  * Single source of truth — import this instead of hardcoding.
4
+ *
5
+ * The list is partitioned deliberately. A type is either a LOCATOR STRATEGY (the resolver's
6
+ * strategy switch turns it into a Playwright/WDIO locator) or a NON-STRATEGY declaration (the
7
+ * entry describes something other than how to find an element, and a reader downstream of the
8
+ * resolver consumes it). A type that is in neither set but is still accepted as valid is drift:
9
+ * it reaches the switch's `default:` and resolves as `getByPlaceholder('<whatever value held>')`,
10
+ * a selector that cannot match. `upload` sat in exactly that gap — valid, documented, and
11
+ * silently mis-resolved (issue #690).
12
+ *
13
+ * Keep the partition total. `tests/codegen/selector-type-dispatch.run.ts` fails if a new member
14
+ * of VALID_SELECTOR_TYPES is classified into neither half, or if a strategy type stops being
15
+ * dispatched and starts resolving as a placeholder.
4
16
  */
5
- export declare const VALID_SELECTOR_TYPES: readonly ["placeholder", "role", "testid", "label", "text", "page", "column", "locator", "id", "upload", "frame", "table", "accessibility-id", "xpath", "android-uiautomator", "ios-predicate", "css"];
17
+ /**
18
+ * Types the resolver turns into a locator. Every member MUST be dispatched in
19
+ * `SelectorResolver.resolveFromEntry` — either by a `case` in its strategy switch or by an
20
+ * early return above it (`locator` and `upload` share one). The contract is on the RESOLVED
21
+ * STRATEGY, not on the syntax used to produce it.
22
+ */
23
+ export declare const STRATEGY_SELECTOR_TYPES: readonly ["placeholder", "role", "testid", "label", "text", "locator", "id", "upload", "accessibility-id", "xpath", "android-uiautomator", "ios-predicate", "css"];
24
+ /**
25
+ * Types that declare something OTHER than a locator strategy, so they have no `case` by design.
26
+ * Each is read after resolution via `ResolvedSelector.selectorType`, or by the pattern that owns
27
+ * the step, which reads the entry's fields directly:
28
+ *
29
+ * page — `value` is a URL path, not a locator. The page assertion reads `selectorType`
30
+ * AFTER resolving (see StepMapper.checkPageStepFallback), so this type must
31
+ * pass through the switch rather than throw.
32
+ * table — the table patterns read `columns` (StepMapper's column-index lookup), `rows` (the
33
+ * row templates, backed by SG-W016) and `pagination` (the paginate step, #712) off
34
+ * the entry. `pagination` was the NOTE that used to sit here: documented, plumbed,
35
+ * and read by nothing — the same drift shape as #690, one level down. It has a
36
+ * consumer now, and SG-W004 is the gate that makes the next such field fail a check
37
+ * rather than wait to be grepped.
38
+ * column — addressed through its table's `columns` map, never resolved standalone.
39
+ * frame — consumed by the frame-enter/exit steps, which need the raw iframe selector.
40
+ *
41
+ * Reaching the strategy switch is legitimate for these; the placeholder fallback there is inert
42
+ * because no consumer reads `strategy` for them.
43
+ */
44
+ export declare const NON_STRATEGY_SELECTOR_TYPES: readonly ["page", "column", "frame", "table"];
45
+ export declare const VALID_SELECTOR_TYPES: readonly ["placeholder", "role", "testid", "label", "text", "locator", "id", "upload", "accessibility-id", "xpath", "android-uiautomator", "ios-predicate", "css", "page", "column", "frame", "table"];
46
+ export type StrategySelectorType = (typeof STRATEGY_SELECTOR_TYPES)[number];
47
+ export type NonStrategySelectorType = (typeof NON_STRATEGY_SELECTOR_TYPES)[number];
6
48
  export type SelectorType = (typeof VALID_SELECTOR_TYPES)[number];
7
49
  //# sourceMappingURL=selector-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"selector-types.d.ts","sourceRoot":"","sources":["../../src/utils/selector-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,wMAmBvB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"selector-types.d.ts","sourceRoot":"","sources":["../../src/utils/selector-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,oKAe1B,CAAC;AAEX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,2BAA2B,+CAK9B,CAAC;AAEX,eAAO,MAAM,oBAAoB,wMAGvB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AACnF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -1,23 +1,37 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VALID_SELECTOR_TYPES = void 0;
4
2
  /**
5
3
  * Valid selector types used across scaffold generator, selector resolver, and validator.
6
4
  * Single source of truth — import this instead of hardcoding.
5
+ *
6
+ * The list is partitioned deliberately. A type is either a LOCATOR STRATEGY (the resolver's
7
+ * strategy switch turns it into a Playwright/WDIO locator) or a NON-STRATEGY declaration (the
8
+ * entry describes something other than how to find an element, and a reader downstream of the
9
+ * resolver consumes it). A type that is in neither set but is still accepted as valid is drift:
10
+ * it reaches the switch's `default:` and resolves as `getByPlaceholder('<whatever value held>')`,
11
+ * a selector that cannot match. `upload` sat in exactly that gap — valid, documented, and
12
+ * silently mis-resolved (issue #690).
13
+ *
14
+ * Keep the partition total. `tests/codegen/selector-type-dispatch.run.ts` fails if a new member
15
+ * of VALID_SELECTOR_TYPES is classified into neither half, or if a strategy type stops being
16
+ * dispatched and starts resolving as a placeholder.
7
17
  */
8
- exports.VALID_SELECTOR_TYPES = [
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.VALID_SELECTOR_TYPES = exports.NON_STRATEGY_SELECTOR_TYPES = exports.STRATEGY_SELECTOR_TYPES = void 0;
20
+ /**
21
+ * Types the resolver turns into a locator. Every member MUST be dispatched in
22
+ * `SelectorResolver.resolveFromEntry` — either by a `case` in its strategy switch or by an
23
+ * early return above it (`locator` and `upload` share one). The contract is on the RESOLVED
24
+ * STRATEGY, not on the syntax used to produce it.
25
+ */
26
+ exports.STRATEGY_SELECTOR_TYPES = [
9
27
  'placeholder',
10
28
  'role',
11
29
  'testid',
12
30
  'label',
13
31
  'text',
14
- 'page',
15
- 'column',
16
32
  'locator',
17
33
  'id',
18
34
  'upload',
19
- 'frame',
20
- 'table',
21
35
  // === Mobile (Appium) strategies — resolved by the appium adapter (MOB-3) ===
22
36
  'accessibility-id', // cross-platform — Android content-desc / iOS accessibilityIdentifier
23
37
  'xpath', // cross-platform, last resort
@@ -25,4 +39,34 @@ exports.VALID_SELECTOR_TYPES = [
25
39
  'ios-predicate', // iOS only — NSPredicate strings
26
40
  'css', // hybrid WebView only — CSS inside a WEBVIEW context (after `switch to [X] frame`)
27
41
  ];
42
+ /**
43
+ * Types that declare something OTHER than a locator strategy, so they have no `case` by design.
44
+ * Each is read after resolution via `ResolvedSelector.selectorType`, or by the pattern that owns
45
+ * the step, which reads the entry's fields directly:
46
+ *
47
+ * page — `value` is a URL path, not a locator. The page assertion reads `selectorType`
48
+ * AFTER resolving (see StepMapper.checkPageStepFallback), so this type must
49
+ * pass through the switch rather than throw.
50
+ * table — the table patterns read `columns` (StepMapper's column-index lookup), `rows` (the
51
+ * row templates, backed by SG-W016) and `pagination` (the paginate step, #712) off
52
+ * the entry. `pagination` was the NOTE that used to sit here: documented, plumbed,
53
+ * and read by nothing — the same drift shape as #690, one level down. It has a
54
+ * consumer now, and SG-W004 is the gate that makes the next such field fail a check
55
+ * rather than wait to be grepped.
56
+ * column — addressed through its table's `columns` map, never resolved standalone.
57
+ * frame — consumed by the frame-enter/exit steps, which need the raw iframe selector.
58
+ *
59
+ * Reaching the strategy switch is legitimate for these; the placeholder fallback there is inert
60
+ * because no consumer reads `strategy` for them.
61
+ */
62
+ exports.NON_STRATEGY_SELECTOR_TYPES = [
63
+ 'page',
64
+ 'column',
65
+ 'frame',
66
+ 'table',
67
+ ];
68
+ exports.VALID_SELECTOR_TYPES = [
69
+ ...exports.STRATEGY_SELECTOR_TYPES,
70
+ ...exports.NON_STRATEGY_SELECTOR_TYPES,
71
+ ];
28
72
  //# sourceMappingURL=selector-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"selector-types.js","sourceRoot":"","sources":["../../src/utils/selector-types.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,oBAAoB,GAAG;IAClC,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,QAAQ;IACR,SAAS;IACT,IAAI;IACJ,QAAQ;IACR,OAAO;IACP,OAAO;IACP,8EAA8E;IAC9E,kBAAkB,EAAK,sEAAsE;IAC7F,OAAO,EAAgB,8BAA8B;IACrD,qBAAqB,EAAE,wCAAwC;IAC/D,eAAe,EAAQ,iCAAiC;IACxD,KAAK,EAAkB,mFAAmF;CAClG,CAAC"}
1
+ {"version":3,"file":"selector-types.js","sourceRoot":"","sources":["../../src/utils/selector-types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH;;;;;GAKG;AACU,QAAA,uBAAuB,GAAG;IACrC,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;IACP,MAAM;IACN,SAAS;IACT,IAAI;IACJ,QAAQ;IACR,8EAA8E;IAC9E,kBAAkB,EAAK,sEAAsE;IAC7F,OAAO,EAAgB,8BAA8B;IACrD,qBAAqB,EAAE,wCAAwC;IAC/D,eAAe,EAAQ,iCAAiC;IACxD,KAAK,EAAkB,mFAAmF;CAClG,CAAC;AAEX;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,2BAA2B,GAAG;IACzC,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;CACC,CAAC;AAEE,QAAA,oBAAoB,GAAG;IAClC,GAAG,+BAAuB;IAC1B,GAAG,mCAA2B;CACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.2.28",
3
+ "version": "3.2.30",
4
4
  "description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -40,8 +40,8 @@
40
40
  "@babel/types": "^7.28.5",
41
41
  "@cucumber/gherkin": "^37.0.0",
42
42
  "@cucumber/messages": "^31.0.0",
43
- "@sungen/driver-data-factory": "3.2.28",
44
- "@sungen/driver-ui": "3.2.28",
43
+ "@sungen/driver-data-factory": "3.2.30",
44
+ "@sungen/driver-ui": "3.2.30",
45
45
  "chalk": "^5.6.2",
46
46
  "commander": "^14.0.2",
47
47
  "dotenv": "^17.2.3",