@sun-asterisk/sungen 3.2.0-beta.142 → 3.2.0-beta.143

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 (242) hide show
  1. package/dist/capabilities/context-router.d.ts +11 -2
  2. package/dist/capabilities/context-router.d.ts.map +1 -1
  3. package/dist/capabilities/context-router.js +10 -3
  4. package/dist/capabilities/context-router.js.map +1 -1
  5. package/dist/capabilities/discover.js +1 -1
  6. package/dist/capabilities/discover.js.map +1 -1
  7. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +54 -0
  8. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -0
  9. package/dist/generators/test-generator/adapters/appium/appium-adapter.js +52 -0
  10. package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -0
  11. package/dist/generators/test-generator/adapters/appium/templates/after-all.hbs +8 -0
  12. package/dist/generators/test-generator/adapters/appium/templates/after-each.hbs +8 -0
  13. package/dist/generators/test-generator/adapters/appium/templates/before-all.hbs +8 -0
  14. package/dist/generators/test-generator/adapters/appium/templates/before-each.hbs +8 -0
  15. package/dist/generators/test-generator/adapters/appium/templates/imports.hbs +8 -0
  16. package/dist/generators/test-generator/adapters/appium/templates/scenario.hbs +8 -0
  17. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-accept-action.hbs +4 -0
  18. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-dismiss-action.hbs +2 -0
  19. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +2 -0
  20. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/check-action.hbs +10 -0
  21. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/clear-action.hbs +1 -0
  22. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-action.hbs +1 -0
  23. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +2 -0
  24. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-select-action.hbs +4 -0
  25. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/dismiss-action.hbs +3 -0
  26. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +6 -0
  27. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/drag-action.hbs +2 -0
  28. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/expand-action.hbs +2 -0
  29. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/fill-action.hbs +14 -0
  30. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/fill-editor-action.hbs +12 -0
  31. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +6 -0
  32. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-exit-action.hbs +2 -0
  33. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hide-keyboard-action.hbs +4 -0
  34. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +2 -0
  35. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/keyboard-global-action.hbs +2 -0
  36. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/press-action.hbs +4 -0
  37. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/radio-select-action.hbs +4 -0
  38. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +19 -0
  39. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/select-action.hbs +5 -0
  40. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/table-action-in-row.hbs +2 -0
  41. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +3 -0
  42. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/uncheck-action.hbs +8 -0
  43. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +2 -0
  44. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/upload-action.hbs +3 -0
  45. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-page.hbs +3 -0
  46. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-role-with-data.hbs +2 -0
  47. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-role.hbs +3 -0
  48. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/alert-text-assertion.hbs +2 -0
  49. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/attribute-assertion.hbs +1 -0
  50. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/checked-assertion.hbs +1 -0
  51. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/clipboard-text-assertion.hbs +2 -0
  52. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/column-cell-assertion.hbs +2 -0
  53. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +14 -0
  54. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/count-assertion.hbs +1 -0
  55. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/disabled-assertion.hbs +1 -0
  56. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/empty-assertion.hbs +1 -0
  57. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/enabled-assertion.hbs +1 -0
  58. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/focused-assertion.hbs +1 -0
  59. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-text-assertion.hbs +15 -0
  60. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +1 -0
  61. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  62. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +12 -0
  63. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/list-item-count-assertion.hbs +2 -0
  64. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/loading-assertion.hbs +2 -0
  65. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/not-checked-assertion.hbs +1 -0
  66. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/page-assertion.hbs +1 -0
  67. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/route-assertion.hbs +2 -0
  68. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/selected-assertion.hbs +1 -0
  69. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/sorted-assertion.hbs +2 -0
  70. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-column-exists.hbs +2 -0
  71. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-empty.hbs +2 -0
  72. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-match-data.hbs +2 -0
  73. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-count.hbs +2 -0
  74. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-exists.hbs +2 -0
  75. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-not-exists.hbs +2 -0
  76. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -0
  77. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/background-action.hbs +1 -0
  78. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/grant-permission-action.hbs +11 -0
  79. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +5 -0
  80. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/open-notifications-action.hbs +3 -0
  81. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +5 -0
  82. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pull-to-refresh-action.hbs +5 -0
  83. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/rotate-action.hbs +1 -0
  84. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-clipboard-action.hbs +2 -0
  85. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +2 -0
  86. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/swipe-action.hbs +5 -0
  87. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/tap-top-action.hbs +24 -0
  88. package/dist/generators/test-generator/adapters/appium/templates/steps/navigation/navigation.hbs +1 -0
  89. package/dist/generators/test-generator/adapters/appium/templates/steps/navigation/wait-for-element-with-text.hbs +1 -0
  90. package/dist/generators/test-generator/adapters/appium/templates/steps/navigation/wait-for-element.hbs +1 -0
  91. package/dist/generators/test-generator/adapters/appium/templates/steps/navigation/wait-timeout.hbs +1 -0
  92. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/appium-selector-expr.hbs +8 -0
  93. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/appium-selector.hbs +15 -0
  94. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +8 -0
  95. package/dist/generators/test-generator/adapters/appium/templates/steps/setup/application-running.hbs +1 -0
  96. package/dist/generators/test-generator/adapters/appium/templates/steps/setup/clear-auth.hbs +2 -0
  97. package/dist/generators/test-generator/adapters/appium/templates/steps/setup/clear-browser-state.hbs +1 -0
  98. package/dist/generators/test-generator/adapters/appium/templates/steps/setup/clear-database.hbs +1 -0
  99. package/dist/generators/test-generator/adapters/appium/templates/steps/setup/user-login-todo.hbs +2 -0
  100. package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +226 -0
  101. package/dist/generators/test-generator/adapters/index.d.ts +1 -0
  102. package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
  103. package/dist/generators/test-generator/adapters/index.js +9 -1
  104. package/dist/generators/test-generator/adapters/index.js.map +1 -1
  105. package/dist/generators/test-generator/step-mapper.d.ts +1 -0
  106. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  107. package/dist/generators/test-generator/step-mapper.js +7 -37
  108. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  109. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  110. package/dist/generators/test-generator/template-engine.js +13 -1
  111. package/dist/generators/test-generator/template-engine.js.map +1 -1
  112. package/dist/harness/audit.d.ts +1 -1
  113. package/dist/harness/audit.d.ts.map +1 -1
  114. package/dist/harness/audit.js +14 -4
  115. package/dist/harness/audit.js.map +1 -1
  116. package/dist/harness/catalog/drivers.yaml +1 -1
  117. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  118. package/dist/orchestrator/ai-rules-updater.js +8 -0
  119. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  120. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-mobile.md +184 -0
  121. package/dist/orchestrator/templates/ai-instructions/claude-skill-mobile-gestures.md +109 -0
  122. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix-mobile.md +316 -0
  123. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mobile.md +184 -0
  124. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-mobile-gestures.md +109 -0
  125. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix-mobile.md +316 -0
  126. package/dist/orchestrator/templates/env.appium.example +25 -0
  127. package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +92 -0
  128. package/dist/orchestrator/templates/wdio.conf.ts +295 -0
  129. package/dist/utils/selector-types.d.ts +1 -1
  130. package/dist/utils/selector-types.d.ts.map +1 -1
  131. package/dist/utils/selector-types.js +5 -0
  132. package/dist/utils/selector-types.js.map +1 -1
  133. package/package.json +3 -3
  134. package/src/capabilities/context-router.ts +15 -3
  135. package/src/capabilities/discover.ts +1 -1
  136. package/src/generators/test-generator/adapters/appium/appium-adapter.ts +57 -0
  137. package/src/generators/test-generator/adapters/appium/templates/after-all.hbs +8 -0
  138. package/src/generators/test-generator/adapters/appium/templates/after-each.hbs +8 -0
  139. package/src/generators/test-generator/adapters/appium/templates/before-all.hbs +8 -0
  140. package/src/generators/test-generator/adapters/appium/templates/before-each.hbs +8 -0
  141. package/src/generators/test-generator/adapters/appium/templates/imports.hbs +8 -0
  142. package/src/generators/test-generator/adapters/appium/templates/scenario.hbs +8 -0
  143. package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-accept-action.hbs +4 -0
  144. package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-dismiss-action.hbs +2 -0
  145. package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +2 -0
  146. package/src/generators/test-generator/adapters/appium/templates/steps/actions/check-action.hbs +10 -0
  147. package/src/generators/test-generator/adapters/appium/templates/steps/actions/clear-action.hbs +1 -0
  148. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-action.hbs +1 -0
  149. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +2 -0
  150. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-select-action.hbs +4 -0
  151. package/src/generators/test-generator/adapters/appium/templates/steps/actions/dismiss-action.hbs +3 -0
  152. package/src/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +6 -0
  153. package/src/generators/test-generator/adapters/appium/templates/steps/actions/drag-action.hbs +2 -0
  154. package/src/generators/test-generator/adapters/appium/templates/steps/actions/expand-action.hbs +2 -0
  155. package/src/generators/test-generator/adapters/appium/templates/steps/actions/fill-action.hbs +14 -0
  156. package/src/generators/test-generator/adapters/appium/templates/steps/actions/fill-editor-action.hbs +12 -0
  157. package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +6 -0
  158. package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-exit-action.hbs +2 -0
  159. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hide-keyboard-action.hbs +4 -0
  160. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +2 -0
  161. package/src/generators/test-generator/adapters/appium/templates/steps/actions/keyboard-global-action.hbs +2 -0
  162. package/src/generators/test-generator/adapters/appium/templates/steps/actions/press-action.hbs +4 -0
  163. package/src/generators/test-generator/adapters/appium/templates/steps/actions/radio-select-action.hbs +4 -0
  164. package/src/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +19 -0
  165. package/src/generators/test-generator/adapters/appium/templates/steps/actions/select-action.hbs +5 -0
  166. package/src/generators/test-generator/adapters/appium/templates/steps/actions/table-action-in-row.hbs +2 -0
  167. package/src/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +3 -0
  168. package/src/generators/test-generator/adapters/appium/templates/steps/actions/uncheck-action.hbs +8 -0
  169. package/src/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +2 -0
  170. package/src/generators/test-generator/adapters/appium/templates/steps/actions/upload-action.hbs +3 -0
  171. package/src/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-page.hbs +3 -0
  172. package/src/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-role-with-data.hbs +2 -0
  173. package/src/generators/test-generator/adapters/appium/templates/steps/actions/wait-for-role.hbs +3 -0
  174. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/alert-text-assertion.hbs +2 -0
  175. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/attribute-assertion.hbs +1 -0
  176. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/checked-assertion.hbs +1 -0
  177. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/clipboard-text-assertion.hbs +2 -0
  178. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/column-cell-assertion.hbs +2 -0
  179. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +14 -0
  180. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/count-assertion.hbs +1 -0
  181. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/disabled-assertion.hbs +1 -0
  182. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/empty-assertion.hbs +1 -0
  183. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/enabled-assertion.hbs +1 -0
  184. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/focused-assertion.hbs +1 -0
  185. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-text-assertion.hbs +15 -0
  186. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +1 -0
  187. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  188. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +12 -0
  189. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/list-item-count-assertion.hbs +2 -0
  190. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/loading-assertion.hbs +2 -0
  191. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/not-checked-assertion.hbs +1 -0
  192. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/page-assertion.hbs +1 -0
  193. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/route-assertion.hbs +2 -0
  194. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/selected-assertion.hbs +1 -0
  195. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/sorted-assertion.hbs +2 -0
  196. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-column-exists.hbs +2 -0
  197. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-empty.hbs +2 -0
  198. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-match-data.hbs +2 -0
  199. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-count.hbs +2 -0
  200. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-exists.hbs +2 -0
  201. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/table-row-not-exists.hbs +2 -0
  202. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -0
  203. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/background-action.hbs +1 -0
  204. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/grant-permission-action.hbs +11 -0
  205. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +5 -0
  206. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/open-notifications-action.hbs +3 -0
  207. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +5 -0
  208. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pull-to-refresh-action.hbs +5 -0
  209. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/rotate-action.hbs +1 -0
  210. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-clipboard-action.hbs +2 -0
  211. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +2 -0
  212. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/swipe-action.hbs +5 -0
  213. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/tap-top-action.hbs +24 -0
  214. package/src/generators/test-generator/adapters/appium/templates/steps/navigation/navigation.hbs +1 -0
  215. package/src/generators/test-generator/adapters/appium/templates/steps/navigation/wait-for-element-with-text.hbs +1 -0
  216. package/src/generators/test-generator/adapters/appium/templates/steps/navigation/wait-for-element.hbs +1 -0
  217. package/src/generators/test-generator/adapters/appium/templates/steps/navigation/wait-timeout.hbs +1 -0
  218. package/src/generators/test-generator/adapters/appium/templates/steps/partials/appium-selector-expr.hbs +8 -0
  219. package/src/generators/test-generator/adapters/appium/templates/steps/partials/appium-selector.hbs +15 -0
  220. package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +8 -0
  221. package/src/generators/test-generator/adapters/appium/templates/steps/setup/application-running.hbs +1 -0
  222. package/src/generators/test-generator/adapters/appium/templates/steps/setup/clear-auth.hbs +2 -0
  223. package/src/generators/test-generator/adapters/appium/templates/steps/setup/clear-browser-state.hbs +1 -0
  224. package/src/generators/test-generator/adapters/appium/templates/steps/setup/clear-database.hbs +1 -0
  225. package/src/generators/test-generator/adapters/appium/templates/steps/setup/user-login-todo.hbs +2 -0
  226. package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +226 -0
  227. package/src/generators/test-generator/adapters/index.ts +7 -0
  228. package/src/generators/test-generator/step-mapper.ts +8 -5
  229. package/src/generators/test-generator/template-engine.ts +13 -1
  230. package/src/harness/audit.ts +12 -4
  231. package/src/harness/catalog/drivers.yaml +1 -1
  232. package/src/orchestrator/ai-rules-updater.ts +8 -0
  233. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mobile.md +184 -0
  234. package/src/orchestrator/templates/ai-instructions/claude-skill-mobile-gestures.md +109 -0
  235. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix-mobile.md +316 -0
  236. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mobile.md +184 -0
  237. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-mobile-gestures.md +109 -0
  238. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix-mobile.md +316 -0
  239. package/src/orchestrator/templates/env.appium.example +25 -0
  240. package/src/orchestrator/templates/specs-pw-shape-reporter.ts +92 -0
  241. package/src/orchestrator/templates/wdio.conf.ts +295 -0
  242. package/src/utils/selector-types.ts +5 -0
@@ -8,6 +8,12 @@ export interface RouteTask {
8
8
  artifact: string;
9
9
  /** Capability tags present on the target (e.g. ['@query'], ['@api'], ['@cases']). */
10
10
  tags?: string[];
11
+ /**
12
+ * The project's active platform (qa/capabilities.yaml `platform:` — web | mobile | …). A platform
13
+ * capability (mobile/native) is activated by the project's platform, NOT by a tag, so it is keyed
14
+ * separately. `web` has no capability id of its own (the in-core default is `ui`) → no-op.
15
+ */
16
+ platform?: string;
11
17
  }
12
18
  export interface RoutePlan {
13
19
  /** Applicable capability ids: the default/implicit one + any whose annotations match the tags. */
@@ -23,8 +29,11 @@ export interface RoutePlan {
23
29
  };
24
30
  }
25
31
  declare class ContextRouter {
26
- /** Which capabilities a set of tags activates: the default capability + any owning a present tag. */
27
- capabilitiesFor(tags?: string[]): string[];
32
+ /**
33
+ * Which capabilities a task activates: the default capability + the active platform's capability
34
+ * (when one is registered with `id === platform`) + any capability owning a present tag.
35
+ */
36
+ capabilitiesFor(tags?: string[], platform?: string): string[];
28
37
  /** Compute the routing plan for a task (deterministic). */
29
38
  route(task: RouteTask): RoutePlan;
30
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"context-router.d.ts","sourceRoot":"","sources":["../../src/capabilities/context-router.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,sGAAsG;IACtG,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,kGAAkG;IAClG,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mDAAmD;IACnD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,mFAAmF;IACnF,KAAK,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC/D;AAED,cAAM,aAAa;IACjB,qGAAqG;IACrG,eAAe,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE;IAU9C,2DAA2D;IAC3D,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS;CAclC;AAED,8BAA8B;AAC9B,eAAO,MAAM,aAAa,eAAsB,CAAC"}
1
+ {"version":3,"file":"context-router.d.ts","sourceRoot":"","sources":["../../src/capabilities/context-router.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,sGAAsG;IACtG,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,kGAAkG;IAClG,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mDAAmD;IACnD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,mFAAmF;IACnF,KAAK,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC/D;AAED,cAAM,aAAa;IACjB;;;OAGG;IACH,eAAe,CAAC,IAAI,GAAE,MAAM,EAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAajE,2DAA2D;IAC3D,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS;CAclC;AAED,8BAA8B;AAC9B,eAAO,MAAM,aAAa,eAAsB,CAAC"}
@@ -16,12 +16,19 @@ exports.contextRouter = void 0;
16
16
  */
17
17
  const registry_1 = require("./registry");
18
18
  class ContextRouter {
19
- /** Which capabilities a set of tags activates: the default capability + any owning a present tag. */
20
- capabilitiesFor(tags = []) {
19
+ /**
20
+ * Which capabilities a task activates: the default capability + the active platform's capability
21
+ * (when one is registered with `id === platform`) + any capability owning a present tag.
22
+ */
23
+ capabilitiesFor(tags = [], platform) {
21
24
  const ids = new Set();
22
25
  const def = registry_1.capabilityRegistry.defaultCapabilityId();
23
26
  if (def)
24
27
  ids.add(def);
28
+ // A platform capability (mobile/native/…) is activated by the project's platform, not by a tag.
29
+ // `web` has no capability of its own → falls through to the default `ui` (byte-identical).
30
+ if (platform && registry_1.capabilityRegistry.get(platform))
31
+ ids.add(platform);
25
32
  for (const cap of registry_1.capabilityRegistry.all()) {
26
33
  if ((cap.annotations ?? []).some((a) => tags.includes(a)))
27
34
  ids.add(cap.id);
@@ -30,7 +37,7 @@ class ContextRouter {
30
37
  }
31
38
  /** Compute the routing plan for a task (deterministic). */
32
39
  route(task) {
33
- const capabilities = this.capabilitiesFor(task.tags ?? []);
40
+ const capabilities = this.capabilitiesFor(task.tags ?? [], task.platform);
34
41
  // Generic sensors (no capability, or the always-on `core`) run regardless of the task's tags;
35
42
  // capability-specific sensors run only when their capability is in scope.
36
43
  const inScope = (capId) => capId == null || capId === 'core' || capabilities.includes(capId);
@@ -1 +1 @@
1
- {"version":3,"file":"context-router.js","sourceRoot":"","sources":["../../src/capabilities/context-router.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,yCAAgD;AAsBhD,MAAM,aAAa;IACjB,qGAAqG;IACrG,eAAe,CAAC,OAAiB,EAAE;QACjC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,MAAM,GAAG,GAAG,6BAAkB,CAAC,mBAAmB,EAAE,CAAC;QACrD,IAAI,GAAG;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,KAAK,MAAM,GAAG,IAAI,6BAAkB,CAAC,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,IAAe;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC3D,8FAA8F;QAC9F,0EAA0E;QAC1E,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,MAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtG,MAAM,aAAa,GAAG,6BAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/G,MAAM,iBAAiB,GAAG,6BAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvH,OAAO;YACL,YAAY;YACZ,aAAa;YACb,iBAAiB;YACjB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;SAC7C,CAAC;IACJ,CAAC;CACF;AAED,8BAA8B;AACjB,QAAA,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"context-router.js","sourceRoot":"","sources":["../../src/capabilities/context-router.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,yCAAgD;AA4BhD,MAAM,aAAa;IACjB;;;OAGG;IACH,eAAe,CAAC,OAAiB,EAAE,EAAE,QAAiB;QACpD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,MAAM,GAAG,GAAG,6BAAkB,CAAC,mBAAmB,EAAE,CAAC;QACrD,IAAI,GAAG;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,gGAAgG;QAChG,2FAA2F;QAC3F,IAAI,QAAQ,IAAI,6BAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACpE,KAAK,MAAM,GAAG,IAAI,6BAAkB,CAAC,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,IAAe;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1E,8FAA8F;QAC9F,0EAA0E;QAC1E,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,MAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtG,MAAM,aAAa,GAAG,6BAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/G,MAAM,iBAAiB,GAAG,6BAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvH,OAAO;YACL,YAAY;YACZ,aAAa;YACb,iBAAiB;YACjB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;SAC7C,CAAC;IACJ,CAAC;CACF;AAED,8BAA8B;AACjB,QAAA,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC"}
@@ -58,7 +58,7 @@ const builtins_1 = require("./builtins");
58
58
  * move to their packages (R5.5/R5.6) they join this list and leave `LOCAL_DRIVERS`; eventually this
59
59
  * becomes a scan of installed `@sungen/driver-*` packages (R5.7).
60
60
  */
61
- const EXTERNAL_DRIVERS = ['@sungen/driver-ui', '@sungen/driver-db', '@sungen/driver-api'];
61
+ const EXTERNAL_DRIVERS = ['@sungen/driver-ui', '@sungen/driver-db', '@sungen/driver-api', '@sungen/driver-mobile'];
62
62
  function loadExternalDriver(name) {
63
63
  // Resolve from the user's PROJECT first, then from core's own location. Opt-in drivers
64
64
  // (`sungen capability add db|api`) install into the PROJECT's node_modules — a globally-installed
@@ -1 +1 @@
1
- {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/capabilities/discover.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,0EAKC;AA7DD;;;;;;;;;;;;;;GAcG;AACH,mCAAuC;AACvC,2CAA6B;AAC7B,yCAAgD;AAChD,yCAAmE;AAEnE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,oBAAoB,CAAC,CAAC;AAE1F,SAAS,kBAAkB,CAAC,IAAY;IACtC,uFAAuF;IACvF,kGAAkG;IAClG,mGAAmG;IACnG,8EAA8E;IAC9E,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC;QAC5E,IAAI,GAAgB,CAAC;QACrB,IAAI,CAAC;YAAC,GAAG,GAAG,IAAA,sBAAa,EAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QACxD,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YAAC,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC,CAAC,0CAA0C;QACpG,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1B,MAAM,QAAQ,GAAyD,GAAG,EAAE,YAAY,EAAE,QAAQ,IAAI,GAAG,EAAE,QAAQ,CAAC;YACpH,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAE,QAAQ,CAAC,6BAAkB,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,6FAA6F;YAC7F,+FAA+F;YAC/F,mDAAmD;YACnD,OAAO,CAAC,IAAI,CACV,gCAAgC,IAAI,iDAAiD;gBACrF,KAAM,CAAW,EAAE,OAAO,IAAI,CAAC,IAAI;gBACnC,gDAAgD,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,mBAAmB,CACzG,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,gFAAgF;IAC1F,CAAC;IACD,0EAA0E;AAC5E,CAAC;AAED,SAAgB,+BAA+B;IAC7C,IAAI,6BAAkB,CAAC,WAAW,EAAE;QAAE,OAAO;IAC7C,KAAK,MAAM,IAAI,IAAI,gBAAgB;QAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,4CAA4C;IAC3G,KAAK,MAAM,MAAM,IAAI,wBAAa;QAAE,MAAM,CAAC,QAAQ,CAAC,6BAAkB,CAAC,CAAC,CAAC,4BAA4B;IACrG,IAAA,iCAAsB,EAAC,6BAAkB,CAAC,CAAC,CAAC,iDAAiD;AAC/F,CAAC"}
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/capabilities/discover.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,0EAKC;AA7DD;;;;;;;;;;;;;;GAcG;AACH,mCAAuC;AACvC,2CAA6B;AAC7B,yCAAgD;AAChD,yCAAmE;AAEnE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,uBAAuB,CAAC,CAAC;AAEnH,SAAS,kBAAkB,CAAC,IAAY;IACtC,uFAAuF;IACvF,kGAAkG;IAClG,mGAAmG;IACnG,8EAA8E;IAC9E,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC;QAC5E,IAAI,GAAgB,CAAC;QACrB,IAAI,CAAC;YAAC,GAAG,GAAG,IAAA,sBAAa,EAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QACxD,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YAAC,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC,CAAC,0CAA0C;QACpG,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1B,MAAM,QAAQ,GAAyD,GAAG,EAAE,YAAY,EAAE,QAAQ,IAAI,GAAG,EAAE,QAAQ,CAAC;YACpH,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAE,QAAQ,CAAC,6BAAkB,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,6FAA6F;YAC7F,+FAA+F;YAC/F,mDAAmD;YACnD,OAAO,CAAC,IAAI,CACV,gCAAgC,IAAI,iDAAiD;gBACrF,KAAM,CAAW,EAAE,OAAO,IAAI,CAAC,IAAI;gBACnC,gDAAgD,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,mBAAmB,CACzG,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,gFAAgF;IAC1F,CAAC;IACD,0EAA0E;AAC5E,CAAC;AAED,SAAgB,+BAA+B;IAC7C,IAAI,6BAAkB,CAAC,WAAW,EAAE;QAAE,OAAO;IAC7C,KAAK,MAAM,IAAI,IAAI,gBAAgB;QAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,4CAA4C;IAC3G,KAAK,MAAM,MAAM,IAAI,wBAAa;QAAE,MAAM,CAAC,QAAQ,CAAC,6BAAkB,CAAC,CAAC,CAAC,4BAA4B;IACrG,IAAA,iCAAsB,EAAC,6BAAkB,CAAC,CAAC,CAAC,iDAAiD;AAC/F,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { TestGeneratorAdapter, TestFileData, ScenarioData } from '../adapter-interface';
2
+ /**
3
+ * AppiumAdapter
4
+ * Generates WebdriverIO + Appium (Mocha) test code using Handlebars templates.
5
+ *
6
+ * Mirrors PlaywrightAdapter: the adapter only renders the file skeleton (imports,
7
+ * describe/it, before/after hooks). Per-step code is produced by StepMapper +
8
+ * PatternRegistry driving this adapter's templates/ directory — the templates here
9
+ * carry the same names the patterns request (click-action, fill-action,
10
+ * visible-assertion, the `locator` partial, …) but emit WebdriverIO instead of Playwright.
11
+ */
12
+ export declare class AppiumAdapter implements TestGeneratorAdapter {
13
+ readonly frameworkName = "appium";
14
+ readonly fileExtension = ".spec.ts";
15
+ readonly templatesDir: string;
16
+ private templateEngine;
17
+ constructor();
18
+ renderTestFile(data: TestFileData): string;
19
+ renderScenario(data: ScenarioData): string;
20
+ renderImports(options?: {
21
+ runtimeData?: boolean;
22
+ basePath?: string;
23
+ isParallel?: boolean;
24
+ needsCleanupImport?: boolean;
25
+ needsDb?: boolean;
26
+ needsApi?: boolean;
27
+ }): string;
28
+ renderBeforeEach(data: {
29
+ steps: Array<{
30
+ comment?: string;
31
+ code: string;
32
+ }>;
33
+ }): string;
34
+ renderBeforeAll(data: {
35
+ steps: Array<{
36
+ comment?: string;
37
+ code: string;
38
+ }>;
39
+ }): string;
40
+ renderAfterEach(data: {
41
+ steps: Array<{
42
+ comment?: string;
43
+ code: string;
44
+ }>;
45
+ }): string;
46
+ renderAfterAll(data: {
47
+ steps: Array<{
48
+ comment?: string;
49
+ code: string;
50
+ }>;
51
+ }): string;
52
+ renderStep(templateName: string, data: any): string;
53
+ }
54
+ //# sourceMappingURL=appium-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-adapter.d.ts","sourceRoot":"","sources":["../../../../../src/generators/test-generator/adapters/appium/appium-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGxF;;;;;;;;;GASG;AACH,qBAAa,aAAc,YAAW,oBAAoB;IACxD,QAAQ,CAAC,aAAa,YAAY;IAClC,QAAQ,CAAC,aAAa,cAAc;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,cAAc,CAAiB;;IAOvC,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM;IAI1C,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM;IAI1C,aAAa,CAAC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAIxK,gBAAgB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,MAAM;IAIpF,eAAe,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,MAAM;IAInF,eAAe,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,MAAM;IAInF,cAAc,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,MAAM;IAIlF,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM;CAGpD"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AppiumAdapter = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const template_engine_1 = require("../../template-engine");
9
+ /**
10
+ * AppiumAdapter
11
+ * Generates WebdriverIO + Appium (Mocha) test code using Handlebars templates.
12
+ *
13
+ * Mirrors PlaywrightAdapter: the adapter only renders the file skeleton (imports,
14
+ * describe/it, before/after hooks). Per-step code is produced by StepMapper +
15
+ * PatternRegistry driving this adapter's templates/ directory — the templates here
16
+ * carry the same names the patterns request (click-action, fill-action,
17
+ * visible-assertion, the `locator` partial, …) but emit WebdriverIO instead of Playwright.
18
+ */
19
+ class AppiumAdapter {
20
+ constructor() {
21
+ this.frameworkName = 'appium';
22
+ this.fileExtension = '.spec.ts';
23
+ this.templatesDir = path_1.default.join(__dirname, 'templates');
24
+ this.templateEngine = new template_engine_1.TemplateEngine(this.templatesDir);
25
+ }
26
+ renderTestFile(data) {
27
+ return this.templateEngine.renderTestFile(data);
28
+ }
29
+ renderScenario(data) {
30
+ return this.templateEngine.renderScenario(data);
31
+ }
32
+ renderImports(options) {
33
+ return this.templateEngine.renderImports(options);
34
+ }
35
+ renderBeforeEach(data) {
36
+ return this.templateEngine.renderBeforeEach(data);
37
+ }
38
+ renderBeforeAll(data) {
39
+ return this.templateEngine.renderBeforeAll(data);
40
+ }
41
+ renderAfterEach(data) {
42
+ return this.templateEngine.renderAfterEach(data);
43
+ }
44
+ renderAfterAll(data) {
45
+ return this.templateEngine.renderAfterAll(data);
46
+ }
47
+ renderStep(templateName, data) {
48
+ return this.templateEngine.renderStep(templateName, data);
49
+ }
50
+ }
51
+ exports.AppiumAdapter = AppiumAdapter;
52
+ //# sourceMappingURL=appium-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-adapter.js","sourceRoot":"","sources":["../../../../../src/generators/test-generator/adapters/appium/appium-adapter.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,2DAAuD;AAEvD;;;;;;;;;GASG;AACH,MAAa,aAAa;IAMxB;QALS,kBAAa,GAAG,QAAQ,CAAC;QACzB,kBAAa,GAAG,UAAU,CAAC;QAKlC,IAAI,CAAC,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QACtD,IAAI,CAAC,cAAc,GAAG,IAAI,gCAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED,cAAc,CAAC,IAAkB;QAC/B,OAAO,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,cAAc,CAAC,IAAkB;QAC/B,OAAO,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,aAAa,CAAC,OAAiJ;QAC7J,OAAO,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,gBAAgB,CAAC,IAA0D;QACzE,OAAO,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,eAAe,CAAC,IAA0D;QACxE,OAAO,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,eAAe,CAAC,IAA0D;QACxE,OAAO,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,cAAc,CAAC,IAA0D;QACvE,OAAO,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,IAAS;QACxC,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;CACF;AA1CD,sCA0CC"}
@@ -0,0 +1,8 @@
1
+ after(async () => {
2
+ {{#each steps}}
3
+ {{#if comment}}
4
+ // {{comment}}
5
+ {{/if}}
6
+ {{code}}
7
+ {{/each}}
8
+ });
@@ -0,0 +1,8 @@
1
+ afterEach(async () => {
2
+ {{#each steps}}
3
+ {{#if comment}}
4
+ // {{comment}}
5
+ {{/if}}
6
+ {{code}}
7
+ {{/each}}
8
+ });
@@ -0,0 +1,8 @@
1
+ before(async () => {
2
+ {{#each steps}}
3
+ {{#if comment}}
4
+ // {{comment}}
5
+ {{/if}}
6
+ {{code}}
7
+ {{/each}}
8
+ });
@@ -0,0 +1,8 @@
1
+ beforeEach(async () => {
2
+ {{#each steps}}
3
+ {{#if comment}}
4
+ // {{comment}}
5
+ {{/if}}
6
+ {{code}}
7
+ {{/each}}
8
+ });
@@ -0,0 +1,8 @@
1
+ import { $, $$, expect, driver, browser } from '@wdio/globals';
2
+ {{#if runtimeData}}
3
+ import { TestDataLoader } from '{{basePath}}/test-data';
4
+ {{/if}}
5
+
6
+ // This file is auto-generated from Gherkin feature files
7
+ // DO NOT EDIT MANUALLY - changes will be overwritten
8
+ // To modify tests, edit the corresponding .feature file and regenerate
@@ -0,0 +1,8 @@
1
+ it('{{scenarioName}}', async () => {
2
+ {{#each steps}}
3
+ {{#if comment}}
4
+ // {{comment}}
5
+ {{/if}}
6
+ {{code}}
7
+ {{/each}}
8
+ });
@@ -0,0 +1,4 @@
1
+ {{!-- Accept a native alert. Unlike web (handler set before the trigger), mobile alerts are handled
2
+ AFTER they appear; for launch-time permission dialogs prefer the `appium:autoAcceptAlerts` cap.
3
+ Best-effort: ignore if no alert is present. --}}
4
+ try { await driver.acceptAlert(); } catch { /* no native alert present */ }
@@ -0,0 +1,2 @@
1
+ {{!-- Dismiss a native alert (best-effort; ignore if none present). --}}
2
+ try { await driver.dismissAlert(); } catch { /* no native alert present */ }
@@ -0,0 +1,2 @@
1
+ {{!-- Filling a native prompt is iOS-specific and app-dependent; Android rarely has fillable alerts.
2
+ Requested value: '{{fillValue}}'. Handle manually if your alert has a text field. --}}
@@ -0,0 +1,10 @@
1
+ {{!-- WebdriverIO/Appium has no .check(). Read the current state and tap only if it's not already
2
+ on, so the step is idempotent (re-running a passing test won't flip it back off). Falls through
3
+ to a plain tap if the state can't be read. --}}
4
+ {
5
+ const __cb = await {{> locator}};
6
+ let __on = false;
7
+ try { __on = await __cb.isSelected(); }
8
+ catch { try { __on = (await __cb.getAttribute('checked')) === 'true'; } catch { /* state unreadable — tap anyway */ } }
9
+ if (!__on) await __cb.click();
10
+ }
@@ -0,0 +1,2 @@
1
+ {{!-- Tap an element by its visible text / content-desc (dynamic text match). --}}
2
+ {{#if nth}}await $$('//*[contains(@content-desc,"{{escapeQuotes dataValue}}") or contains(@text,"{{escapeQuotes dataValue}}")]')[{{nth}}].click();{{else}}await $('//*[contains(@content-desc,"{{escapeQuotes dataValue}}") or contains(@text,"{{escapeQuotes dataValue}}")]').click();{{/if}}
@@ -0,0 +1,4 @@
1
+ {{!-- Custom (non-native) select: open the control, then tap the option by accessibility-id /
2
+ content-desc (= the option value). Same two-tap shape as select-action on mobile. --}}
3
+ await {{> locator}}.click();
4
+ await $('~{{escapeQuotes selectValue}}').click();
@@ -0,0 +1,3 @@
1
+ // Best-effort dismiss (launch interstitial / promo / ad): tap if it shows within a short grace,
2
+ // otherwise skip — never fails the step.
3
+ try { const __d = await {{> locator}}; if (await __d.waitForDisplayed({ timeout: 2500 }).then(() => true).catch(() => false)) await __d.click(); } catch { /* not present — skip */ }
@@ -0,0 +1,6 @@
1
+ {{!-- Double-tap. Use the platform gesture (element.doubleClick is web-oriented). --}}
2
+ {
3
+ const __el = await {{> locator}};
4
+ if (driver.isIOS) await driver.execute('mobile: doubleTap', { elementId: __el.elementId });
5
+ else await driver.execute('mobile: doubleClickGesture', { elementId: __el.elementId });
6
+ }
@@ -0,0 +1,2 @@
1
+ {{!-- Drag the source element onto the target. WebdriverIO dragAndDrop drives W3C touch actions. --}}
2
+ await (await {{> locator}}).dragAndDrop(await $('{{#switch targetStrategy}}{{#case 'accessibility-id'}}~{{escapeQuotes targetValue}}{{/case}}{{#case 'testid'}}~{{escapeQuotes targetValue}}{{/case}}{{#case 'xpath'}}{{escapeQuotes targetValue}}{{/case}}{{#case 'android-uiautomator'}}android={{escapeQuotes targetValue}}{{/case}}{{#case 'id'}}id={{escapeQuotes targetValue}}{{/case}}{{#default}}~{{#if targetValue}}{{escapeQuotes targetValue}}{{else}}{{escapeQuotes targetName}}{{/if}}{{/default}}{{/switch}}'));
@@ -0,0 +1,2 @@
1
+ {{!-- Mobile has no aria-expanded to verify; expanding/collapsing a row or accordion is just a tap. --}}
2
+ await {{> locator}}.click();
@@ -0,0 +1,14 @@
1
+ {{!-- Robust mobile fill: Flutter often ignores a bare setValue (the field never registers, so a
2
+ dependent submit button stays disabled). Explicitly focus, clear, setValue, then if the field
3
+ still reads empty, retype with addValue. Best-effort read-back never fails the step. --}}
4
+ {
5
+ const __fill = await {{> locator}};
6
+ await __fill.click();
7
+ try { await __fill.clearValue(); } catch { /* not clearable */ }
8
+ await __fill.setValue('{{escapeQuotes fillValue}}');
9
+ try {
10
+ const __got = (await __fill.getText()) || (await __fill.getAttribute('text')) || '';
11
+ const __masked = /[•●*]/.test(__got);
12
+ if (!__masked && __got.trim() === '') await __fill.addValue('{{escapeQuotes fillValue}}');
13
+ } catch { /* read-back unsupported — trust setValue */ }
14
+ }
@@ -0,0 +1,12 @@
1
+ {{!-- Rich-text/contenteditable editors don't exist as such on native mobile — treat as a normal field
2
+ with the robust fill (focus, clear, setValue, read-back, retry). --}}
3
+ {
4
+ const __fill = await {{> locator}};
5
+ await __fill.click();
6
+ try { await __fill.clearValue(); } catch { /* not clearable */ }
7
+ await __fill.setValue('{{escapeQuotes fillValue}}');
8
+ try {
9
+ const __got = (await __fill.getText()) || (await __fill.getAttribute('text')) || '';
10
+ if (!/[•●*]/.test(__got) && __got.trim() === '') await __fill.addValue('{{escapeQuotes fillValue}}');
11
+ } catch { /* read-back unsupported — trust setValue */ }
12
+ }
@@ -0,0 +1,6 @@
1
+ {{!-- Hybrid app: switch into the webview context (mobile equivalent of entering an iframe). --}}
2
+ {
3
+ const __ctxs = await driver.getContexts();
4
+ const __web = __ctxs.find(c => /WEBVIEW|CHROMIUM/i.test(typeof c === 'string' ? c : c.id));
5
+ if (__web) await driver.switchContext(typeof __web === 'string' ? __web : __web.id);
6
+ }
@@ -0,0 +1,2 @@
1
+ {{!-- Back to the native context. --}}
2
+ await driver.switchContext('NATIVE_APP');
@@ -0,0 +1,4 @@
1
+ // Hide the soft keyboard (best-effort — never fails if no keyboard is shown).
2
+ // iOS XCUITest cannot dismiss the keyboard generically (WDA throws + retries, ~12s wasted),
3
+ // and XCUITest taps/asserts work with the keyboard up — so the dismiss is Android-only.
4
+ try { if (!driver.isIOS && await driver.isKeyboardShown()) await driver.hideKeyboard(); } catch { /* no keyboard / not supported */ }
@@ -0,0 +1,2 @@
1
+ {{!-- No hover on touch devices — no-op. (Hover-revealed content is normally already visible on mobile;
2
+ if a tap is actually required, use `User tap [X]` instead.) --}}
@@ -0,0 +1,2 @@
1
+ {{!-- Global key event (no target). On Android, Escape maps to the system Back button. --}}
2
+ {{#if (eq key 'Escape')}}await driver.back();{{else}}await driver.keys('{{key}}');{{/if}}
@@ -0,0 +1,4 @@
1
+ {{!-- Press a key on a field (e.g. Enter after filling a search box). Focus the field, then send the
2
+ W3C key event — UiAutomator2/XCUITest translate it to a real key press. --}}
3
+ await {{> locator}}.click();
4
+ await driver.keys('{{key}}');
@@ -0,0 +1,4 @@
1
+ {{!-- Mobile radios have no ARIA "radio" role to query by name, so tap the option by its
2
+ accessibility-id / content-desc (= the option value). If the visible label differs from the
3
+ element's accessibility-id, add an explicit selector for the option and reference it instead. --}}
4
+ await $('~{{escapeQuotes selectValue}}').click();
@@ -0,0 +1,19 @@
1
+ if (driver.isIOS) {
2
+ // iOS (XCUITest) has no UiScrollable. Swipe the screen up in bounded steps until the target is on
3
+ // screen (a below-fold element isn't in the XCUITest tree until scrolled, so getElementRect/tap on
4
+ // it would otherwise fail). Bounded so a missing target can't loop forever.
5
+ const __t = $({{> appium-selector-expr}});
6
+ for (let __i = 0; __i < 12 && !(await __t.isDisplayed().catch(() => false)); __i++) {
7
+ await driver.execute('mobile: swipe', { direction: 'up' });
8
+ }
9
+ } else {
10
+ {{#if (eq strategy 'accessibility-id')}}
11
+ // Android UiScrollable scrolls until the target's content-desc is on screen, then stops — no
12
+ // overshoot (which would drop a virtualized Flutter item from the a11y tree). Robust on Flutter/RN.
13
+ await $('android=new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().descriptionContains("{{escapeQuotes value}}"))');
14
+ {{else}}
15
+ // Generic fallback: framework-agnostic moderate scroll gesture (wdio .scrollIntoView() can't always
16
+ // find a native ScrollView on Flutter/RN). Modest percent avoids over-scrolling a virtualized list.
17
+ await driver.execute('mobile: scrollGesture', { left: 60, top: 420, width: 960, height: 1320, direction: 'down', percent: 0.6 });
18
+ {{/if}}
19
+ }
@@ -0,0 +1,5 @@
1
+ {{!-- Native dropdown/picker: open the control, then tap the option by accessibility-id /
2
+ content-desc (= the option value). Two taps because there is no native <select>.selectOption
3
+ on mobile. If the option's accessibility-id differs from its label, add an explicit selector. --}}
4
+ await {{> locator}}.click();
5
+ await $('~{{escapeQuotes selectValue}}').click();
@@ -0,0 +1,2 @@
1
+ {{!-- Table row actions target HTML <table> roles — not available on native mobile. --}}
2
+ throw new Error("[sungen] 'table action in row' targets HTML table roles and is not supported on the appium adapter. Use list / accessibility-id steps, or tag this scenario @manual.");
@@ -0,0 +1,3 @@
1
+ {{!-- A switch/toggle flips state on tap (mirrors the web toggle pattern: unconditional click).
2
+ Use `check`/`uncheck` instead when you need to drive it to a specific on/off state idempotently. --}}
3
+ await {{> locator}}.click();
@@ -0,0 +1,8 @@
1
+ {{!-- WebdriverIO/Appium has no .uncheck(). Tap only if currently on, so the step is idempotent. --}}
2
+ {
3
+ const __cb = await {{> locator}};
4
+ let __on = false;
5
+ try { __on = await __cb.isSelected(); }
6
+ catch { try { __on = (await __cb.getAttribute('checked')) === 'true'; } catch { /* state unreadable — leave as-is */ } }
7
+ if (__on) await __cb.click();
8
+ }
@@ -0,0 +1,2 @@
1
+ {{!-- Fallback for an unrecognized action: tap an element by text / content-desc. --}}
2
+ await $('//*[contains(@content-desc,"{{escapeQuotes dataValue}}") or contains(@text,"{{escapeQuotes dataValue}}")]').click();
@@ -0,0 +1,3 @@
1
+ {{!-- File upload is not auto-generatable on native mobile (no <input type=file>): it needs app-specific
2
+ handling (driver.pushFile + the app's own picker, or a deep link). Fail loud so it isn't a silent skip. --}}
3
+ throw new Error("[sungen] upload step ('{{fileName}}') is not supported on the appium adapter — handle the file picker app-specifically (driver.pushFile + picker) or tag this scenario @manual.");
@@ -0,0 +1,3 @@
1
+ {{!-- No URL/page concept on mobile. Pause briefly to let the screen settle; prefer a screen-marker
2
+ assertion (`Then User see [X] ...`) over waiting for a "page". --}}
3
+ await driver.pause(500);
@@ -0,0 +1,2 @@
1
+ {{!-- No ARIA role on mobile; wait for an element carrying the given text instead. --}}
2
+ await $('//*[contains(@content-desc,"{{escapeQuotes dataValue}}") or contains(@text,"{{escapeQuotes dataValue}}")]').waitForDisplayed();
@@ -0,0 +1,3 @@
1
+ {{!-- ARIA roles don't exist on native mobile; no element to wait for from a role alone. Pause briefly.
2
+ Rewrite as `wait for [Element]` for a real wait. --}}
3
+ await driver.pause(500);
@@ -0,0 +1,2 @@
1
+ {{!-- Assert the native alert's text. --}}
2
+ expect(await driver.getAlertText()).toContain('{{escapeQuotes expectedText}}');
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toHaveAttribute('{{attribute}}', '{{escapeQuotes dataValue}}');
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toBeSelected();
@@ -0,0 +1,2 @@
1
+ {{!-- Assert the device clipboard content (decode the base64 Appium returns). --}}
2
+ expect(Buffer.from(await driver.getClipboard(), 'base64').toString()).toContain(String({{#if dataRef}}testData.get('{{dataRef}}'){{else}}'{{escapeQuotes expectedValue}}'{{/if}}));
@@ -0,0 +1,2 @@
1
+ {{!-- Table/column steps target HTML <table> ARIA roles — not available on native mobile. --}}
2
+ throw new Error("[sungen] table/column steps target HTML table roles and are not supported on the appium adapter. Use list / accessibility-id assertions, or tag this scenario @manual.");
@@ -0,0 +1,14 @@
1
+ {{!-- Partial-text assertion (mobile): same multi-source read as have-text-assertion
2
+ (@text / @content-desc on Android, label/value on iOS), substring match. --}}
3
+ {
4
+ const __el = await {{> locator}};
5
+ await __el.waitForDisplayed();
6
+ const __expected = String('{{escapeQuotes expectedText}}').trim();
7
+ const __sources = driver.isIOS
8
+ ? [await __el.getAttribute('label'), await __el.getAttribute('value')]
9
+ : [await __el.getText(), await __el.getAttribute('content-desc')];
10
+ const __actual = String(__sources.find(s => s && String(s).trim() !== '') ?? '').trim();
11
+ if (!__actual.includes(__expected)) {
12
+ throw new Error(`[sungen] Expected text containing "${__expected}" but element reads "${__actual}"`);
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ await expect($$('{{> appium-selector}}')).toBeElementsArrayOfSize({{expectedCount}});
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).not.toBeEnabled();
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toHaveText('');
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toBeEnabled();
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toBeFocused();
@@ -0,0 +1,15 @@
1
+ {{!-- Text assertion (mobile): native trees scatter text across @text (Android RN/native),
2
+ @content-desc (Android Flutter Semantics) and label/value (iOS). Read the first
3
+ non-empty source and compare exactly (trimmed). --}}
4
+ {
5
+ const __el = await {{> locator}};
6
+ await __el.waitForDisplayed();
7
+ const __expected = String('{{escapeQuotes expectedText}}').trim();
8
+ const __sources = driver.isIOS
9
+ ? [await __el.getAttribute('label'), await __el.getAttribute('value')]
10
+ : [await __el.getText(), await __el.getAttribute('content-desc')];
11
+ const __actual = String(__sources.find(s => s && String(s).trim() !== '') ?? '').trim();
12
+ if (__actual !== __expected) {
13
+ throw new Error(`[sungen] Expected text "${__expected}" but element reads "${__actual}"`);
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toHaveValue('{{escapeQuotes dataValue}}');
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).not.toBeDisplayed();
@@ -0,0 +1,12 @@
1
+ {{!-- Label-value assertion (mobile): locate a visible text node carrying the value.
2
+ Android renders text into @text; iOS (RN/Flutter) into @label/@value. The web variant
3
+ matches "label: value" as one string — native trees keep label and value as separate
4
+ nodes, so only the value is matched here. The expected value must stay a standalone
5
+ quoted literal so the runtime-data transform can swap it for testData.get(...). --}}
6
+ {
7
+ const __expected = String('{{escapeQuotes dataValue}}').trim();
8
+ const __sel = driver.isIOS
9
+ ? `-ios predicate string:label == "${__expected}" OR value == "${__expected}"`
10
+ : `android=new UiSelector().text("${__expected}")`;
11
+ await expect($(__sel)).toBeDisplayed();
12
+ }
@@ -0,0 +1,2 @@
1
+ {{!-- Count the elements matching the list locator (mobile has no role="listitem"). --}}
2
+ await expect($$('{{> appium-selector}}')).toBeElementsArrayOfSize({{expectedCount}});
@@ -0,0 +1,2 @@
1
+ {{!-- Mobile has no aria-busy; assert the loading indicator element itself is visible. --}}
2
+ await expect({{> locator}}).toBeDisplayed();
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).not.toBeSelected();
@@ -0,0 +1 @@
1
+ // page/URL assertion is not applicable on mobile (no URL) — [{{value}}]
@@ -0,0 +1,2 @@
1
+ {{!-- URL/route assertions have no equivalent on native mobile (no address bar). --}}
2
+ throw new Error("[sungen] URL/route assertions are web-only — assert a screen marker (`Then User see [X] ...`) instead, or tag this scenario @manual.");
@@ -0,0 +1 @@
1
+ await expect({{> locator}}).toBeSelected();
@@ -0,0 +1,2 @@
1
+ {{!-- aria-sort has no native-mobile equivalent. --}}
2
+ throw new Error("[sungen] 'sorted' assertion (aria-sort) is web-only and has no native-mobile equivalent. Verify order by reading element texts and comparing, or tag this scenario @manual.");