swipium 1.5.0 → 2.0.1

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 (498) hide show
  1. package/CHANGELOG.md +183 -0
  2. package/README.md +173 -280
  3. package/THREAT_MODEL.md +223 -47
  4. package/dist/appMap/automationLink.js +30 -27
  5. package/dist/appMap/automationLink.js.map +1 -1
  6. package/dist/appMap/build.js +47 -21
  7. package/dist/appMap/build.js.map +1 -1
  8. package/dist/appMap/codeIndex.js +2 -2
  9. package/dist/appMap/codeIndex.js.map +1 -1
  10. package/dist/appMap/featureIndex.js +3 -3
  11. package/dist/appMap/featureIndex.js.map +1 -1
  12. package/dist/appMap/featureModel.js +2 -2
  13. package/dist/appMap/featureModel.js.map +1 -1
  14. package/dist/appMap/firstRunApply.js +2 -2
  15. package/dist/appMap/firstRunApply.js.map +1 -1
  16. package/dist/appMap/issues.js +10 -10
  17. package/dist/appMap/issues.js.map +1 -1
  18. package/dist/appMap/migrations.js +5 -5
  19. package/dist/appMap/migrations.js.map +1 -1
  20. package/dist/appMap/prelaunch.js +2 -2
  21. package/dist/appMap/prelaunch.js.map +1 -1
  22. package/dist/appMap/projectRegistry.js +77 -11
  23. package/dist/appMap/projectRegistry.js.map +1 -1
  24. package/dist/appMap/provenance.js +2 -2
  25. package/dist/appMap/provenance.js.map +1 -1
  26. package/dist/appMap/query.js +2 -2
  27. package/dist/appMap/query.js.map +1 -1
  28. package/dist/appMap/runtimeMerge.js +3 -3
  29. package/dist/appMap/runtimeMerge.js.map +1 -1
  30. package/dist/appMap/schema.js +1 -1
  31. package/dist/appMap/schema.js.map +1 -1
  32. package/dist/appMap/screenMatch.js +1 -1
  33. package/dist/appMap/screenMatch.js.map +1 -1
  34. package/dist/appMap/staticScan.js +17 -17
  35. package/dist/appMap/staticScan.js.map +1 -1
  36. package/dist/appMap/store.js +55 -7
  37. package/dist/appMap/store.js.map +1 -1
  38. package/dist/appMap/tsAstScan.js +3 -3
  39. package/dist/appMap/tsAstScan.js.map +1 -1
  40. package/dist/artifacts/bundletool.js +5 -5
  41. package/dist/artifacts/bundletool.js.map +1 -1
  42. package/dist/artifacts/resolve.js +10 -10
  43. package/dist/artifacts/resolve.js.map +1 -1
  44. package/dist/automation/capabilities.js +3 -3
  45. package/dist/automation/capabilities.js.map +1 -1
  46. package/dist/automation/gestures.js +1 -1
  47. package/dist/automation/gestures.js.map +1 -1
  48. package/dist/automation/plan.js +7 -7
  49. package/dist/automation/plan.js.map +1 -1
  50. package/dist/automation/report.js +3 -3
  51. package/dist/automation/report.js.map +1 -1
  52. package/dist/automation/selectors.js +14 -25
  53. package/dist/automation/selectors.js.map +1 -1
  54. package/dist/automation/types.js +1 -1
  55. package/dist/automation/types.js.map +1 -1
  56. package/dist/automation/waits.js +5 -5
  57. package/dist/automation/waits.js.map +1 -1
  58. package/dist/automation/webview.js +2 -2
  59. package/dist/automation/webview.js.map +1 -1
  60. package/dist/automationGen/appiumModel.js +13 -7
  61. package/dist/automationGen/appiumModel.js.map +1 -1
  62. package/dist/automationGen/ciEmitter.js +5 -5
  63. package/dist/automationGen/ciEmitter.js.map +1 -1
  64. package/dist/automationGen/identifiers.js +224 -0
  65. package/dist/automationGen/identifiers.js.map +1 -0
  66. package/dist/automationGen/jsEmitter.js +265 -106
  67. package/dist/automationGen/jsEmitter.js.map +1 -1
  68. package/dist/automationGen/packagePatch.js +2 -2
  69. package/dist/automationGen/packagePatch.js.map +1 -1
  70. package/dist/automationGen/platformResolve.js +36 -0
  71. package/dist/automationGen/platformResolve.js.map +1 -0
  72. package/dist/automationGen/projectProfile.js +71 -26
  73. package/dist/automationGen/projectProfile.js.map +1 -1
  74. package/dist/automationGen/pythonEmitter.js +276 -105
  75. package/dist/automationGen/pythonEmitter.js.map +1 -1
  76. package/dist/automationGen/readmeEmitter.js +7 -6
  77. package/dist/automationGen/readmeEmitter.js.map +1 -1
  78. package/dist/{tools/automationGenerate.js → automationGen/run.js} +72 -113
  79. package/dist/automationGen/run.js.map +1 -0
  80. package/dist/automationGen/suitePlan.js +6 -4
  81. package/dist/automationGen/suitePlan.js.map +1 -1
  82. package/dist/automationGen/validation.js +20 -8
  83. package/dist/automationGen/validation.js.map +1 -1
  84. package/dist/build/parseBuildLog.js +2 -2
  85. package/dist/build/parseBuildLog.js.map +1 -1
  86. package/dist/build/plan.js +7 -7
  87. package/dist/build/plan.js.map +1 -1
  88. package/dist/ci/preflight.js +13 -4
  89. package/dist/ci/preflight.js.map +1 -1
  90. package/dist/cli/gc.js +74 -0
  91. package/dist/cli/gc.js.map +1 -0
  92. package/dist/cli/init.js +217 -26
  93. package/dist/cli/init.js.map +1 -1
  94. package/dist/cli/main.js +50 -0
  95. package/dist/cli/main.js.map +1 -0
  96. package/dist/cli/report.js +218 -0
  97. package/dist/cli/report.js.map +1 -0
  98. package/dist/cli/scan.js +35 -14
  99. package/dist/cli/scan.js.map +1 -1
  100. package/dist/cli/suite.js +6 -6
  101. package/dist/cli/suite.js.map +1 -1
  102. package/dist/cli/verify.js +7 -7
  103. package/dist/cli/verify.js.map +1 -1
  104. package/dist/consent/consent.js +162 -5
  105. package/dist/consent/consent.js.map +1 -1
  106. package/dist/context/detect.js +45 -14
  107. package/dist/context/detect.js.map +1 -1
  108. package/dist/context/findApps.js +6 -6
  109. package/dist/context/findApps.js.map +1 -1
  110. package/dist/context/projectRoot.js +174 -19
  111. package/dist/context/projectRoot.js.map +1 -1
  112. package/dist/context/scan.js +1 -1
  113. package/dist/context/scan.js.map +1 -1
  114. package/dist/core/capabilityGroups.js +90 -0
  115. package/dist/core/capabilityGroups.js.map +1 -0
  116. package/dist/core/target.js +3 -3
  117. package/dist/core/target.js.map +1 -1
  118. package/dist/core/targetPlan.js +65 -62
  119. package/dist/core/targetPlan.js.map +1 -1
  120. package/dist/drivers/DirectDriver.js +300 -36
  121. package/dist/drivers/DirectDriver.js.map +1 -1
  122. package/dist/drivers/SimctlDriver.js +120 -7
  123. package/dist/drivers/SimctlDriver.js.map +1 -1
  124. package/dist/drivers/WdaDriver.js +350 -50
  125. package/dist/drivers/WdaDriver.js.map +1 -1
  126. package/dist/explore/candidates.js +2 -2
  127. package/dist/explore/candidates.js.map +1 -1
  128. package/dist/explore/graph.js +5 -5
  129. package/dist/explore/graph.js.map +1 -1
  130. package/dist/explore/policy.js +5 -5
  131. package/dist/explore/policy.js.map +1 -1
  132. package/dist/explore/runner.js +301 -284
  133. package/dist/explore/runner.js.map +1 -1
  134. package/dist/explore/signatures.js +1 -1
  135. package/dist/featureTesting/executionBootstrap.js +29 -30
  136. package/dist/featureTesting/executionBootstrap.js.map +1 -1
  137. package/dist/featureTesting/featureMap.js +2 -2
  138. package/dist/featureTesting/featureMap.js.map +1 -1
  139. package/dist/featureTesting/featureScope.js +12 -12
  140. package/dist/featureTesting/featureScope.js.map +1 -1
  141. package/dist/featureTesting/mapFeatureScope.js +7 -7
  142. package/dist/featureTesting/mapFeatureScope.js.map +1 -1
  143. package/dist/featureTesting/objectiveModel.js +10 -10
  144. package/dist/featureTesting/objectiveModel.js.map +1 -1
  145. package/dist/featureTesting/resultMerge.js +6 -6
  146. package/dist/featureTesting/resultMerge.js.map +1 -1
  147. package/dist/featureTesting/sources.js +4 -4
  148. package/dist/featureTesting/sources.js.map +1 -1
  149. package/dist/featureTesting/suiteBridge.js +1 -1
  150. package/dist/featureTesting/suiteBridge.js.map +1 -1
  151. package/dist/featureTesting/synonyms.js +1 -1
  152. package/dist/featureTesting/synonyms.js.map +1 -1
  153. package/dist/featureTesting/testCaseFactory.js +11 -11
  154. package/dist/featureTesting/testCaseFactory.js.map +1 -1
  155. package/dist/featureTesting/testPlan.js +3 -3
  156. package/dist/featureTesting/testPlan.js.map +1 -1
  157. package/dist/firstRun/authStateMachine.js +1 -1
  158. package/dist/firstRun/authStateMachine.js.map +1 -1
  159. package/dist/firstRun/classifyScreen.js +5 -5
  160. package/dist/firstRun/classifyScreen.js.map +1 -1
  161. package/dist/firstRun/firstRunPlanner.js +11 -11
  162. package/dist/firstRun/firstRunPlanner.js.map +1 -1
  163. package/dist/firstRun/firstRunRunner.js +8 -8
  164. package/dist/firstRun/firstRunRunner.js.map +1 -1
  165. package/dist/firstRun/generatedDataPolicy.js +9 -9
  166. package/dist/firstRun/generatedDataPolicy.js.map +1 -1
  167. package/dist/firstRun/inputPlanner.js +5 -5
  168. package/dist/firstRun/inputPlanner.js.map +1 -1
  169. package/dist/firstRun/onboardingStateMachine.js +1 -1
  170. package/dist/firstRun/onboardingStateMachine.js.map +1 -1
  171. package/dist/firstRun/paywallPolicy.js +3 -3
  172. package/dist/firstRun/paywallPolicy.js.map +1 -1
  173. package/dist/firstRun/types.js +1 -1
  174. package/dist/firstRun/types.js.map +1 -1
  175. package/dist/fixtures/catalog.js +33 -3
  176. package/dist/fixtures/catalog.js.map +1 -1
  177. package/dist/fixtures/load.js +50 -0
  178. package/dist/fixtures/load.js.map +1 -0
  179. package/dist/flows/discover.js +2 -2
  180. package/dist/flows/discover.js.map +1 -1
  181. package/dist/flows/generate.js +20 -10
  182. package/dist/flows/generate.js.map +1 -1
  183. package/dist/flows/pack.js +3 -3
  184. package/dist/flows/pack.js.map +1 -1
  185. package/dist/flows/paths.js +57 -0
  186. package/dist/flows/paths.js.map +1 -0
  187. package/dist/flows/repair.js +111 -23
  188. package/dist/flows/repair.js.map +1 -1
  189. package/dist/flows/run.js +153 -57
  190. package/dist/flows/run.js.map +1 -1
  191. package/dist/flows/schema.js +50 -5
  192. package/dist/flows/schema.js.map +1 -1
  193. package/dist/flows/seedExec.js +4 -4
  194. package/dist/flows/seedExec.js.map +1 -1
  195. package/dist/flows/templates.js +5 -5
  196. package/dist/index.js +50 -8
  197. package/dist/index.js.map +1 -1
  198. package/dist/issues/classify.js +16 -16
  199. package/dist/issues/classify.js.map +1 -1
  200. package/dist/issues/fingerprint.js +24 -4
  201. package/dist/issues/fingerprint.js.map +1 -1
  202. package/dist/issues/index.js +94 -31
  203. package/dist/issues/index.js.map +1 -1
  204. package/dist/issues/metrics.js +4 -4
  205. package/dist/issues/metrics.js.map +1 -1
  206. package/dist/issues/recurrence.js +35 -8
  207. package/dist/issues/recurrence.js.map +1 -1
  208. package/dist/issues/report.js +4 -4
  209. package/dist/issues/report.js.map +1 -1
  210. package/dist/issues/reportBridge.js +4 -4
  211. package/dist/issues/reportBridge.js.map +1 -1
  212. package/dist/issues/schema.js +2 -2
  213. package/dist/issues/schema.js.map +1 -1
  214. package/dist/issues/sourceRevision.js +2 -2
  215. package/dist/issues/sourceRevision.js.map +1 -1
  216. package/dist/issues/store.js +110 -32
  217. package/dist/issues/store.js.map +1 -1
  218. package/dist/lib/abortScope.js +48 -0
  219. package/dist/lib/abortScope.js.map +1 -0
  220. package/dist/lib/android.js +75 -7
  221. package/dist/lib/android.js.map +1 -1
  222. package/dist/lib/coordSpace.js +1 -1
  223. package/dist/lib/coordSpace.js.map +1 -1
  224. package/dist/lib/device.js +32 -7
  225. package/dist/lib/device.js.map +1 -1
  226. package/dist/lib/gestures.js +141 -0
  227. package/dist/lib/gestures.js.map +1 -0
  228. package/dist/lib/gitignore.js +4 -3
  229. package/dist/lib/gitignore.js.map +1 -1
  230. package/dist/lib/image.js +1 -1
  231. package/dist/lib/image.js.map +1 -1
  232. package/dist/lib/lockfile.js +370 -31
  233. package/dist/lib/lockfile.js.map +1 -1
  234. package/dist/lib/needsInput.js +3 -3
  235. package/dist/lib/needsInput.js.map +1 -1
  236. package/dist/lib/png.js +2 -2
  237. package/dist/lib/png.js.map +1 -1
  238. package/dist/lib/redact.js +170 -9
  239. package/dist/lib/redact.js.map +1 -1
  240. package/dist/lib/result.js +79 -10
  241. package/dist/lib/result.js.map +1 -1
  242. package/dist/lib/schemaHash.js +3 -3
  243. package/dist/lib/schemaHash.js.map +1 -1
  244. package/dist/lib/sensitive.js +3 -2
  245. package/dist/lib/sensitive.js.map +1 -1
  246. package/dist/lib/simctl.js +3 -3
  247. package/dist/lib/simctl.js.map +1 -1
  248. package/dist/lib/spawn.js +52 -10
  249. package/dist/lib/spawn.js.map +1 -1
  250. package/dist/lib/toolAnnotations.js +114 -0
  251. package/dist/lib/toolAnnotations.js.map +1 -0
  252. package/dist/lib/wda.js +294 -15
  253. package/dist/lib/wda.js.map +1 -1
  254. package/dist/mobileAudit/checks.js +12 -12
  255. package/dist/mobileAudit/checks.js.map +1 -1
  256. package/dist/mobileAudit/evidence.js +4 -4
  257. package/dist/mobileAudit/evidence.js.map +1 -1
  258. package/dist/mobileAudit/profiles.js +1 -1
  259. package/dist/mobileAudit/profiles.js.map +1 -1
  260. package/dist/mobileAudit/results.js +3 -3
  261. package/dist/mobileAudit/results.js.map +1 -1
  262. package/dist/mobileAudit/runner.js +72 -18
  263. package/dist/mobileAudit/runner.js.map +1 -1
  264. package/dist/oracle/auth.js +1 -1
  265. package/dist/oracle/auth.js.map +1 -1
  266. package/dist/oracle/failures.js +219 -36
  267. package/dist/oracle/failures.js.map +1 -1
  268. package/dist/oracle/health.js +63 -17
  269. package/dist/oracle/health.js.map +1 -1
  270. package/dist/oracle/locator.js +13 -13
  271. package/dist/oracle/locator.js.map +1 -1
  272. package/dist/oracle/record.js +3 -3
  273. package/dist/oracle/record.js.map +1 -1
  274. package/dist/orchestration/envelope.js +2 -2
  275. package/dist/orchestration/envelope.js.map +1 -1
  276. package/dist/orchestration/goal.js +4 -4
  277. package/dist/orchestration/goal.js.map +1 -1
  278. package/dist/orchestration/testThis/execute.js +62 -21
  279. package/dist/orchestration/testThis/execute.js.map +1 -1
  280. package/dist/orchestration/testThis/pipeline.js +119 -30
  281. package/dist/orchestration/testThis/pipeline.js.map +1 -1
  282. package/dist/orchestration/testThis/plan.js +162 -73
  283. package/dist/orchestration/testThis/plan.js.map +1 -1
  284. package/dist/orchestration/testThis/sessionIntent.js +72 -0
  285. package/dist/orchestration/testThis/sessionIntent.js.map +1 -0
  286. package/dist/orchestration/testThis/terminal.js +34 -16
  287. package/dist/orchestration/testThis/terminal.js.map +1 -1
  288. package/dist/orchestration/testThis/types.js +1 -1
  289. package/dist/orchestration/testThis/types.js.map +1 -1
  290. package/dist/plan/plan.js +9 -9
  291. package/dist/plan/plan.js.map +1 -1
  292. package/dist/prompts/index.js +22 -22
  293. package/dist/prompts/index.js.map +1 -1
  294. package/dist/report/export.js +392 -37
  295. package/dist/report/export.js.map +1 -1
  296. package/dist/report/findingsDedupe.js +41 -0
  297. package/dist/report/findingsDedupe.js.map +1 -0
  298. package/dist/report/policy.js +7 -4
  299. package/dist/report/policy.js.map +1 -1
  300. package/dist/report/qaLevel.js +8 -8
  301. package/dist/report/qaLevel.js.map +1 -1
  302. package/dist/report/sarifSources.js +160 -0
  303. package/dist/report/sarifSources.js.map +1 -0
  304. package/dist/report/summary.js +2 -2
  305. package/dist/report/summary.js.map +1 -1
  306. package/dist/report/testCatalog.js +4 -4
  307. package/dist/report/testCatalog.js.map +1 -1
  308. package/dist/report/toolHealth.js +124 -0
  309. package/dist/report/toolHealth.js.map +1 -0
  310. package/dist/server.js +472 -45
  311. package/dist/server.js.map +1 -1
  312. package/dist/services/automationGenerate.js +8 -2
  313. package/dist/services/automationGenerate.js.map +1 -1
  314. package/dist/services/build.js +2 -2
  315. package/dist/services/build.js.map +1 -1
  316. package/dist/{tools → services}/flowGenerate.js +29 -13
  317. package/dist/services/flowGenerate.js.map +1 -0
  318. package/dist/services/preflight.js +4 -4
  319. package/dist/services/preflight.js.map +1 -1
  320. package/dist/services/prepareAndroid.js +46 -8
  321. package/dist/services/prepareAndroid.js.map +1 -1
  322. package/dist/services/prepareIos.js +24 -9
  323. package/dist/services/prepareIos.js.map +1 -1
  324. package/dist/services/report.js +100 -45
  325. package/dist/services/report.js.map +1 -1
  326. package/dist/services/smoke.js +32 -16
  327. package/dist/services/smoke.js.map +1 -1
  328. package/dist/services/suiteGenerate.js +28 -3
  329. package/dist/services/suiteGenerate.js.map +1 -1
  330. package/dist/services/testSuiteKnowledge.js +40 -27
  331. package/dist/services/testSuiteKnowledge.js.map +1 -1
  332. package/dist/session/attach.js +270 -6
  333. package/dist/session/attach.js.map +1 -1
  334. package/dist/session/processRegistry.js +317 -48
  335. package/dist/session/processRegistry.js.map +1 -1
  336. package/dist/session/progress.js +1 -1
  337. package/dist/session/retention.js +201 -0
  338. package/dist/session/retention.js.map +1 -0
  339. package/dist/session/store.js +275 -48
  340. package/dist/session/store.js.map +1 -1
  341. package/dist/snapshot/overlays.js +53 -8
  342. package/dist/snapshot/overlays.js.map +1 -1
  343. package/dist/snapshot/parse.js +28 -4
  344. package/dist/snapshot/parse.js.map +1 -1
  345. package/dist/snapshot/present.js +11 -5
  346. package/dist/snapshot/present.js.map +1 -1
  347. package/dist/snapshot/settle.js +39 -9
  348. package/dist/snapshot/settle.js.map +1 -1
  349. package/dist/state/consent.js +99 -0
  350. package/dist/state/consent.js.map +1 -0
  351. package/dist/state/profile.js +46 -2
  352. package/dist/state/profile.js.map +1 -1
  353. package/dist/suite/compile.js +9 -5
  354. package/dist/suite/compile.js.map +1 -1
  355. package/dist/suite/lint.js +4 -4
  356. package/dist/suite/lint.js.map +1 -1
  357. package/dist/suite/pom.js +50 -41
  358. package/dist/suite/pom.js.map +1 -1
  359. package/dist/suite/secretGuard.js +266 -0
  360. package/dist/suite/secretGuard.js.map +1 -0
  361. package/dist/suite/testcase.js +9 -7
  362. package/dist/suite/testcase.js.map +1 -1
  363. package/dist/testSuite/exporter.js +4 -4
  364. package/dist/testSuite/exporter.js.map +1 -1
  365. package/dist/testSuite/generator.js +13 -9
  366. package/dist/testSuite/generator.js.map +1 -1
  367. package/dist/testSuite/history.js +1 -1
  368. package/dist/testSuite/history.js.map +1 -1
  369. package/dist/testSuite/issueLinks.js +3 -3
  370. package/dist/testSuite/issueLinks.js.map +1 -1
  371. package/dist/testSuite/lint.js +4 -4
  372. package/dist/testSuite/lint.js.map +1 -1
  373. package/dist/testSuite/merge.js +5 -5
  374. package/dist/testSuite/merge.js.map +1 -1
  375. package/dist/testSuite/schema.js +5 -5
  376. package/dist/testSuite/schema.js.map +1 -1
  377. package/dist/testSuite/store.js +3 -3
  378. package/dist/testSuite/store.js.map +1 -1
  379. package/dist/testSuite/traceability.js +2 -2
  380. package/dist/testSuite/traceability.js.map +1 -1
  381. package/dist/tools/act.js +794 -164
  382. package/dist/tools/act.js.map +1 -1
  383. package/dist/tools/agent.js +451 -128
  384. package/dist/tools/agent.js.map +1 -1
  385. package/dist/tools/appControl.js +69 -19
  386. package/dist/tools/appControl.js.map +1 -1
  387. package/dist/tools/appMap.js +188 -130
  388. package/dist/tools/appMap.js.map +1 -1
  389. package/dist/tools/build.js +32 -42
  390. package/dist/tools/build.js.map +1 -1
  391. package/dist/tools/bundletool.js +21 -31
  392. package/dist/tools/bundletool.js.map +1 -1
  393. package/dist/tools/clearOverlay.js +55 -12
  394. package/dist/tools/clearOverlay.js.map +1 -1
  395. package/dist/tools/device.js +76 -24
  396. package/dist/tools/device.js.map +1 -1
  397. package/dist/tools/doctor.js +68 -28
  398. package/dist/tools/doctor.js.map +1 -1
  399. package/dist/tools/explore.js +41 -47
  400. package/dist/tools/explore.js.map +1 -1
  401. package/dist/tools/featureTesting.js +31 -48
  402. package/dist/tools/featureTesting.js.map +1 -1
  403. package/dist/tools/firstRun.js +34 -41
  404. package/dist/tools/firstRun.js.map +1 -1
  405. package/dist/tools/flow.js +183 -103
  406. package/dist/tools/flow.js.map +1 -1
  407. package/dist/tools/flowRepair.js +25 -13
  408. package/dist/tools/flowRepair.js.map +1 -1
  409. package/dist/tools/generate.js +52 -89
  410. package/dist/tools/generate.js.map +1 -1
  411. package/dist/tools/getArtifact.js +16 -5
  412. package/dist/tools/getArtifact.js.map +1 -1
  413. package/dist/tools/health.js +15 -12
  414. package/dist/tools/health.js.map +1 -1
  415. package/dist/tools/ios.js +45 -223
  416. package/dist/tools/ios.js.map +1 -1
  417. package/dist/tools/issues.js +251 -35
  418. package/dist/tools/issues.js.map +1 -1
  419. package/dist/tools/jobs.js +41 -16
  420. package/dist/tools/jobs.js.map +1 -1
  421. package/dist/tools/metro.js +36 -35
  422. package/dist/tools/metro.js.map +1 -1
  423. package/dist/tools/mobileAudit.js +50 -45
  424. package/dist/tools/mobileAudit.js.map +1 -1
  425. package/dist/tools/network.js +31 -14
  426. package/dist/tools/network.js.map +1 -1
  427. package/dist/tools/note.js +26 -26
  428. package/dist/tools/note.js.map +1 -1
  429. package/dist/tools/prepareIosTarget.js +10 -16
  430. package/dist/tools/prepareIosTarget.js.map +1 -1
  431. package/dist/tools/prepareTarget.js +117 -50
  432. package/dist/tools/prepareTarget.js.map +1 -1
  433. package/dist/tools/report.js +11 -22
  434. package/dist/tools/report.js.map +1 -1
  435. package/dist/tools/resolveArtifact.js +11 -15
  436. package/dist/tools/resolveArtifact.js.map +1 -1
  437. package/dist/tools/resolveTarget.js +78 -24
  438. package/dist/tools/resolveTarget.js.map +1 -1
  439. package/dist/tools/screenRecord.js +23 -21
  440. package/dist/tools/screenRecord.js.map +1 -1
  441. package/dist/tools/screenshot.js +23 -16
  442. package/dist/tools/screenshot.js.map +1 -1
  443. package/dist/tools/smoke.js +20 -16
  444. package/dist/tools/smoke.js.map +1 -1
  445. package/dist/tools/snapshot.js +155 -118
  446. package/dist/tools/snapshot.js.map +1 -1
  447. package/dist/tools/startSession.js +104 -116
  448. package/dist/tools/startSession.js.map +1 -1
  449. package/dist/tools/suite.js +72 -43
  450. package/dist/tools/suite.js.map +1 -1
  451. package/dist/tools/testSuite.js +30 -20
  452. package/dist/tools/testSuite.js.map +1 -1
  453. package/dist/tools/testThis.js +24 -28
  454. package/dist/tools/testThis.js.map +1 -1
  455. package/dist/tools/visual.js +686 -210
  456. package/dist/tools/visual.js.map +1 -1
  457. package/dist/tools/wait.js +9 -38
  458. package/dist/tools/wait.js.map +1 -1
  459. package/dist/tools/wda.js +187 -57
  460. package/dist/tools/wda.js.map +1 -1
  461. package/dist/version.js +31 -22
  462. package/dist/version.js.map +1 -1
  463. package/dist/visual/ocr.js +53 -6
  464. package/dist/visual/ocr.js.map +1 -1
  465. package/dist/visual/provider.js +80 -12
  466. package/dist/visual/provider.js.map +1 -1
  467. package/docs/README.md +24 -10
  468. package/docs/ci-reports.md +328 -0
  469. package/docs/concepts.md +227 -0
  470. package/docs/flows.md +153 -0
  471. package/docs/mcp-server.md +194 -128
  472. package/docs/physical-devices.md +84 -0
  473. package/docs/tools.md +812 -152
  474. package/package.json +3 -2
  475. package/dist/tools/assertVisual.js +0 -84
  476. package/dist/tools/assertVisual.js.map +0 -1
  477. package/dist/tools/automationGenerate.js.map +0 -1
  478. package/dist/tools/capabilities.js +0 -179
  479. package/dist/tools/capabilities.js.map +0 -1
  480. package/dist/tools/detectContext.js +0 -41
  481. package/dist/tools/detectContext.js.map +0 -1
  482. package/dist/tools/flowGenerate.js.map +0 -1
  483. package/dist/tools/history.js +0 -86
  484. package/dist/tools/history.js.map +0 -1
  485. package/dist/tools/locator.js +0 -85
  486. package/dist/tools/locator.js.map +0 -1
  487. package/dist/tools/permissions.js +0 -174
  488. package/dist/tools/permissions.js.map +0 -1
  489. package/dist/tools/plan.js +0 -52
  490. package/dist/tools/plan.js.map +0 -1
  491. package/dist/tools/screenInfo.js +0 -76
  492. package/dist/tools/screenInfo.js.map +0 -1
  493. package/dist/tools/seed.js +0 -133
  494. package/dist/tools/seed.js.map +0 -1
  495. package/dist/tools/state.js +0 -217
  496. package/dist/tools/state.js.map +0 -1
  497. package/dist/tools/visualText.js +0 -106
  498. package/dist/tools/visualText.js.map +0 -1
@@ -1,17 +1,67 @@
1
- // SWIPIUM-REQ-04 — JS/TS WebdriverIO + Appium emitter. Pure: turns the shared Appium model into a
1
+ // JS/TS WebdriverIO + Appium emitter. Pure: turns the shared Appium model into a
2
2
  // runnable WebdriverIO POM suite (page/screen classes with locator getters + action methods, env-
3
3
  // driven capabilities, structured waits). No XPath is ever emitted; coordinate fallbacks are marked
4
4
  // non-release-grade. Aligns with the Appium JS quickstart (WebdriverIO) locator-strategy guidance.
5
+ import { defaultPlatformOf } from './platformResolve.js';
6
+ import { NameAllocator, UnemittableStepError, checkDirection, checkKey, className, commentSafe, isJsIdentifier, jsMemberName, pascalWords, screensOf, } from './identifiers.js';
5
7
  const DEFAULT_TIMEOUT = 15000;
6
- function pascal(s) {
7
- const parts = s
8
- .replace(/[^A-Za-z0-9]+/g, ' ')
9
- .trim()
10
- .split(/\s+/)
11
- .filter(Boolean);
12
- return parts.map((p) => p[0].toUpperCase() + p.slice(1)).join('') || 'X';
8
+ const MAX_SCROLLS = 8;
9
+ /** Every member BaseScreen declares. A generated field/method must never shadow one (a field named
10
+ * `tap` would replace the tap() helper, and in TS it is a type error). */
11
+ const JS_BASE_MEMBERS = [
12
+ 'constructor',
13
+ 'element',
14
+ 'tap',
15
+ 'type',
16
+ 'typeFocused',
17
+ 'scrollTo',
18
+ 'scrollToText',
19
+ 'scrollOnce',
20
+ 'isVisible',
21
+ 'assertVisible',
22
+ 'assertTextVisible',
23
+ 'textSelector',
24
+ 'tapAt',
25
+ 'pressKey',
26
+ 'swipe',
27
+ 'openUrl',
28
+ ];
29
+ function methodKey(action, element) {
30
+ return `${action}|${element}`;
13
31
  }
14
- /** Env var (SWIPIUM_TEST_PASSWORD) → a stable testData key (password). */
32
+ function planJsNames(model) {
33
+ const classes = new NameAllocator(['BaseScreen', 'TestData', 'PlatformLocator'], (s) => s.toLowerCase());
34
+ const instances = new NameAllocator(['testData', 'driver', 'browser', 'describe', 'it', 'expect', '$', '$$']);
35
+ const plan = new Map();
36
+ for (const screen of screensOf(model)) {
37
+ const cls = classes.alloc(className(screen.className));
38
+ const instance = instances.alloc(cls[0].toLowerCase() + cls.slice(1));
39
+ const members = new NameAllocator(JS_BASE_MEMBERS);
40
+ const fields = new Map();
41
+ for (const el of screen.elements)
42
+ if (!fields.has(el.name))
43
+ fields.set(el.name, members.alloc(jsMemberName(el.name)));
44
+ const methods = new Map();
45
+ for (const s of model.steps) {
46
+ if (s.screen !== screen.className || !s.element)
47
+ continue;
48
+ const field = fields.get(s.element);
49
+ if (!field) {
50
+ throw new UnemittableStepError(`cannot emit ${s.action} step on ${screen.className}: element ${JSON.stringify(s.element)} is not declared on that screen`);
51
+ }
52
+ const key = methodKey(s.action, s.element);
53
+ if (methods.has(key))
54
+ continue;
55
+ methods.set(key, members.alloc(methodBase(s.action, pascalWords(field) || 'Element')));
56
+ }
57
+ plan.set(screen.className, { cls, instance, fields, methods });
58
+ }
59
+ return plan;
60
+ }
61
+ function jsProp(obj, key) {
62
+ return isJsIdentifier(key) ? `${obj}.${key}` : `${obj}[${JSON.stringify(key)}]`;
63
+ }
64
+ /** Env var (SWIPIUM_TEST_PASSWORD) > a stable testData key (password). */
15
65
  export function varToKey(v) {
16
66
  const stripped = v.replace(/^SWIPIUM_(TEST_)?/i, '');
17
67
  const parts = stripped
@@ -60,8 +110,11 @@ function platformLocatorLiteral(el) {
60
110
  export function emitJsSuite(input) {
61
111
  const ts = input.language === 'typescript';
62
112
  const ext = ts ? 'ts' : 'js';
63
- const t = (annotation) => (ts ? annotation : '');
64
113
  const files = [];
114
+ // Plan every class/field/method name up front (H4) and validate every step is emittable (§4);
115
+ // generation fails loudly here rather than writing a suite with silent no-op steps.
116
+ const names = planJsNames(input.model);
117
+ const smoke = smokeTest(input.model, names);
65
118
  files.push({ path: 'package.json', content: packageJson(input) });
66
119
  if (ts)
67
120
  files.push({ path: 'tsconfig.json', content: tsconfigJson() });
@@ -70,11 +123,12 @@ export function emitJsSuite(input) {
70
123
  files.push({ path: `src/utils/locators.${ext}`, content: locatorsUtil(ts) });
71
124
  files.push({ path: `src/utils/waits.${ext}`, content: waitsUtil(ts) });
72
125
  files.push({ path: `src/screens/BaseScreen.${ext}`, content: baseScreen(ts) });
73
- for (const screen of input.model.screens) {
74
- files.push({ path: `src/screens/${screen.className}.${ext}`, content: screenClass(screen, input.model.steps, ts, t) });
126
+ for (const screen of screensOf(input.model)) {
127
+ const n = names.get(screen.className);
128
+ files.push({ path: `src/screens/${n.cls}.${ext}`, content: screenClass(screen, n, input.model.steps, ts) });
75
129
  }
76
130
  files.push({ path: `src/data/testData.${ext}`, content: testData(input.model, ts) });
77
- files.push({ path: `test/smoke.e2e.${ext}`, content: smokeTest(input.model, ts) });
131
+ files.push({ path: `test/smoke.e2e.${ext}`, content: smoke });
78
132
  return files;
79
133
  }
80
134
  function packageJson(input) {
@@ -84,7 +138,7 @@ function packageJson(input) {
84
138
  name,
85
139
  private: true,
86
140
  type: 'module',
87
- description: 'Generated by Swipium — WebdriverIO + Appium POM suite (review before committing).',
141
+ description: 'Generated by Swipium: WebdriverIO + Appium POM suite (review before committing).',
88
142
  scripts: {
89
143
  test: 'wdio run ./wdio.conf.' + (ts ? 'ts' : 'js'),
90
144
  },
@@ -115,7 +169,7 @@ function tsconfigJson() {
115
169
  }, null, 2) + '\n');
116
170
  }
117
171
  function wdioConf(ts, ext) {
118
- const header = '// Generated by Swipium. WebdriverIO + Appium config — capabilities come from env (see src/config/capabilities).';
172
+ const header = '// Generated by Swipium. WebdriverIO + Appium config. Capabilities come from env (see src/config/capabilities).';
119
173
  const importLine = `import { buildCapabilities } from './src/config/capabilities.js';`;
120
174
  const typeAnno = ts ? `\nimport type { Options } from '@wdio/types';\n` : '\n';
121
175
  const cfgType = ts ? ': WebdriverIO.Config' : '';
@@ -139,15 +193,17 @@ export const config${cfgType} = {
139
193
  `;
140
194
  }
141
195
  function capabilities(input, ts) {
142
- const android = input.model.platforms.android;
196
+ const primary = defaultPlatformOf(input.profile, input.model);
143
197
  const ret = ts ? ': WebdriverIO.Capabilities' : '';
144
198
  const appId = input.appId ?? '';
145
199
  const lines = [];
146
- lines.push('// Generated by Swipium. ALL device/app config is environment-driven — no secrets, no hardcoded paths.');
147
- lines.push('// Android is the default fast-feedback backend; set SWIPIUM_PLATFORM=ios to target iOS (XCUITest).');
200
+ lines.push('// Generated by Swipium. ALL device/app config is environment-driven: no secrets, no hardcoded paths.');
201
+ lines.push(primary === 'ios'
202
+ ? '// iOS (XCUITest) is the default for this suite; set SWIPIUM_PLATFORM=android to target Android (UiAutomator2).'
203
+ : '// Android (UiAutomator2) is the default for this suite; set SWIPIUM_PLATFORM=ios to target iOS (XCUITest).');
148
204
  lines.push('');
149
205
  lines.push(`export function buildCapabilities()${ret} {`);
150
- lines.push(` const platform = (process.env.SWIPIUM_PLATFORM || ${JSON.stringify(android ? 'android' : 'ios')}).toLowerCase();`);
206
+ lines.push(` const platform = (process.env.SWIPIUM_PLATFORM || ${JSON.stringify(primary)}).toLowerCase();`);
151
207
  lines.push(" if (platform === 'ios') {");
152
208
  lines.push(' return {');
153
209
  lines.push(" platformName: 'iOS',");
@@ -160,7 +216,7 @@ function capabilities(input, ts) {
160
216
  lines.push(" 'appium:noReset': process.env.SWIPIUM_NO_RESET === 'true',");
161
217
  lines.push(' };');
162
218
  lines.push(' }');
163
- lines.push(' // Android UiAutomator2 (default).');
219
+ lines.push(' // Android UiAutomator2.');
164
220
  lines.push(' return {');
165
221
  lines.push(" platformName: 'Android',");
166
222
  lines.push(" 'appium:automationName': 'UiAutomator2',");
@@ -177,7 +233,7 @@ function capabilities(input, ts) {
177
233
  }
178
234
  function locatorsUtil(ts) {
179
235
  const typeBlock = ts
180
- ? `export interface PlatformLocator {\n android?: string;\n ios?: string;\n /** "x,y" coordinate fallback — non-release-grade. */\n coordinate?: string;\n}\n\n`
236
+ ? `export interface PlatformLocator {\n android?: string;\n ios?: string;\n /** "x,y" coordinate fallback, non-release-grade. */\n coordinate?: string;\n}\n\n`
181
237
  : '';
182
238
  const param = ts ? 'loc: PlatformLocator' : 'loc';
183
239
  const ret = ts ? ': string' : '';
@@ -187,7 +243,7 @@ ${typeBlock}export function resolveSelector(${param})${ret} {
187
243
  const android = typeof driver !== 'undefined' ? driver.isAndroid : true;
188
244
  const selector = android ? loc.android : loc.ios;
189
245
  if (!selector) {
190
- throw new Error('No durable selector for this platform — element relies on a coordinate fallback (non-release-grade). Add an accessibility id / resource-id / testID.');
246
+ throw new Error('No durable selector for this platform. Element relies on a coordinate fallback (non-release-grade). Add an accessibility id / resource-id / testID.');
191
247
  }
192
248
  return selector;
193
249
  }
@@ -202,7 +258,7 @@ export function coordinateOf(${param})${ts ? ': [number, number] | undefined' :
202
258
  function waitsUtil(ts) {
203
259
  const elAnno = ts ? ': WebdriverIO.Element' : '';
204
260
  const numAnno = ts ? ': number' : '';
205
- return `// Generated by Swipium. Structured waits — never a bare sleep. Auto-wait before interaction
261
+ return `// Generated by Swipium. Structured waits, never a bare sleep. Auto-wait before interaction
206
262
  // (Playwright-style resilience, applied to mobile Appium).
207
263
  export const DEFAULT_TIMEOUT = ${DEFAULT_TIMEOUT};
208
264
 
@@ -220,36 +276,92 @@ export async function waitEnabled(el${elAnno}, timeout${numAnno} = DEFAULT_TIMEO
220
276
  function baseScreen(ts) {
221
277
  const locImport = ts ? `import type { PlatformLocator } from '../utils/locators.js';\n` : '';
222
278
  const p = (name, type) => (ts ? `${name}: ${type}` : name);
279
+ // H3: TS-only modifiers/annotations are gated on the TypeScript flag so the .js output parses.
280
+ const prot = ts ? 'protected ' : '';
281
+ const dirType = ts ? `: 'up' | 'down' | 'left' | 'right'` : '';
223
282
  return `// Generated by Swipium. BaseScreen centralizes all element interaction so selectors are
224
283
  // resolved per-platform in ONE place and tests never touch raw selectors.
225
- ${locImport}import { resolveSelector, coordinateOf } from '../utils/locators.js';
226
- import { waitVisible, waitEnabled, DEFAULT_TIMEOUT } from '../utils/waits.js';
284
+ ${locImport}import { resolveSelector } from '../utils/locators.js';
285
+ import { waitVisible, waitEnabled } from '../utils/waits.js';
286
+
287
+ /** Upper bound on scroll gestures while looking for an element, so never an endless loop. */
288
+ export const MAX_SCROLLS = ${MAX_SCROLLS};
227
289
 
228
290
  export class BaseScreen {
229
- protected async element(${p('loc', 'PlatformLocator')}) {
291
+ ${prot}async element(${p('loc', 'PlatformLocator')}) {
230
292
  // @ts-ignore wdio global
231
293
  return $(resolveSelector(loc));
232
294
  }
233
295
 
234
- protected async tap(${p('loc', 'PlatformLocator')}) {
296
+ ${prot}async tap(${p('loc', 'PlatformLocator')}) {
235
297
  const el = await this.element(loc);
236
298
  await waitEnabled(await waitVisible(el));
237
299
  await el.click();
238
300
  }
239
301
 
240
- protected async type(${p('loc', 'PlatformLocator')}, ${p('value', 'string')}) {
302
+ ${prot}async type(${p('loc', 'PlatformLocator')}, ${p('value', 'string')}) {
241
303
  const el = await this.element(loc);
242
304
  await waitVisible(el);
243
305
  await el.setValue(value);
244
306
  }
245
307
 
246
- protected async scrollTo(${p('loc', 'PlatformLocator')}) {
247
- const el = await this.element(loc);
248
- await el.scrollIntoView();
249
- await waitVisible(el);
308
+ /** Type into whichever field currently has focus (the recording had no locator for it). */
309
+ async typeFocused(${p('value', 'string')}) {
310
+ // @ts-ignore wdio global
311
+ const active = await $(await driver.getActiveElement());
312
+ await active.addValue(value);
313
+ }
314
+
315
+ /**
316
+ * One real content-scroll gesture. direction is the CONTENT direction: 'down' reveals what is below.
317
+ * Android: UiAutomator2 \`mobile: scrollGesture\` (returns false once the end is reached).
318
+ * iOS: XCUITest \`mobile: scroll\`.
319
+ */
320
+ async scrollOnce(${p('direction', 'string')} = 'down')${ts ? ': Promise<boolean>' : ''} {
321
+ // @ts-ignore wdio global
322
+ if (driver.isAndroid) {
323
+ // @ts-ignore wdio global
324
+ const { width, height } = await driver.getWindowSize();
325
+ // @ts-ignore wdio global
326
+ const canScrollMore = await driver.execute('mobile: scrollGesture', {
327
+ left: Math.round(width * 0.1),
328
+ top: Math.round(height * 0.2),
329
+ width: Math.round(width * 0.8),
330
+ height: Math.round(height * 0.6),
331
+ direction,
332
+ percent: 0.75,
333
+ });
334
+ return canScrollMore !== false;
335
+ }
336
+ // @ts-ignore wdio global
337
+ await driver.execute('mobile: scroll', { direction });
338
+ return true;
339
+ }
340
+
341
+ /** Scroll (bounded by maxScrolls) until the element is displayed; throws if it never appears. */
342
+ ${prot}async scrollTo(${p('loc', 'PlatformLocator')}, ${p('direction', 'string')} = 'down', ${p('maxScrolls', 'number')} = MAX_SCROLLS) {
343
+ let atEnd = false;
344
+ for (let i = 0; i <= maxScrolls; i++) {
345
+ if (await this.isVisible(loc)) return;
346
+ if (i === maxScrolls || atEnd) break;
347
+ atEnd = !(await this.scrollOnce(direction));
348
+ }
349
+ throw new Error('Element not visible after scrolling ' + direction + ' (max ' + maxScrolls + ' scrolls)');
350
+ }
351
+
352
+ /** Scroll (bounded) until an element whose text/label contains \`text\` is displayed. */
353
+ async scrollToText(${p('text', 'string')}, ${p('direction', 'string')} = 'down', ${p('maxScrolls', 'number')} = MAX_SCROLLS) {
354
+ let atEnd = false;
355
+ for (let i = 0; i <= maxScrolls; i++) {
356
+ // @ts-ignore wdio global
357
+ if (await $(this.textSelector(text)).isDisplayed()) return;
358
+ if (i === maxScrolls || atEnd) break;
359
+ atEnd = !(await this.scrollOnce(direction));
360
+ }
361
+ throw new Error('Text ' + JSON.stringify(text) + ' not visible after scrolling ' + direction + ' (max ' + maxScrolls + ' scrolls)');
250
362
  }
251
363
 
252
- protected async isVisible(${p('loc', 'PlatformLocator')})${ts ? ': Promise<boolean>' : ''} {
364
+ ${prot}async isVisible(${p('loc', 'PlatformLocator')})${ts ? ': Promise<boolean>' : ''} {
253
365
  const el = await this.element(loc);
254
366
  return el.isDisplayed();
255
367
  }
@@ -259,28 +371,60 @@ export class BaseScreen {
259
371
  await waitVisible(el);
260
372
  }
261
373
 
374
+ /** Platform-appropriate "text contains" selector. JSON.stringify escapes backslashes and quotes. */
375
+ textSelector(${p('text', 'string')})${ts ? ': string' : ''} {
376
+ // @ts-ignore wdio global
377
+ if (driver.isAndroid) return 'android=new UiSelector().textContains(' + JSON.stringify(text) + ')';
378
+ return '-ios predicate string:label CONTAINS ' + JSON.stringify(text) + ' OR name CONTAINS ' + JSON.stringify(text);
379
+ }
380
+
262
381
  async assertTextVisible(${p('text', 'string')}) {
263
- // Non-release-grade text/OCR assertion — prefer a structured locator.
382
+ // Non-release-grade text/OCR assertion. Prefer a structured locator.
264
383
  // @ts-ignore wdio global
265
- const el = await $('android=new UiSelector().textContains(' + JSON.stringify(text) + ')');
384
+ const el = await $(this.textSelector(text));
266
385
  await waitVisible(el);
267
386
  }
268
387
 
269
- // Coordinate tap — brittle, non-release-grade fallback. Only used when no durable locator exists.
388
+ // Coordinate tap: brittle, non-release-grade fallback. Only used when no durable locator exists.
270
389
  async tapAt(${p('x', 'number')}, ${p('y', 'number')}) {
271
390
  // @ts-ignore wdio global
272
- await driver.action('pointer')
391
+ await driver.action('pointer', { parameters: { pointerType: 'touch' } })
273
392
  .move({ x, y }).down().pause(50).up().perform();
274
393
  }
275
394
 
276
- async pressKey(${p('key', 'string')}) {
277
- // @ts-ignore wdio global
278
- if (driver.isAndroid && key === 'back') { await driver.back(); return; }
395
+ async pressKey(${p('key', `'back' | 'home' | 'enter'`)}) {
279
396
  // @ts-ignore wdio global
280
- await driver.keys([key]);
397
+ const android = driver.isAndroid;
398
+ if (key === 'back') {
399
+ // @ts-ignore wdio global
400
+ if (android) { await driver.back(); return; }
401
+ // iOS has no system back key: swipe in from the left edge (UINavigationController back gesture).
402
+ // @ts-ignore wdio global
403
+ const { width, height } = await driver.getWindowSize();
404
+ // @ts-ignore wdio global
405
+ await driver.action('pointer', { parameters: { pointerType: 'touch' } })
406
+ .move({ x: 2, y: Math.round(height / 2) }).down().pause(50)
407
+ .move({ duration: 400, x: Math.round(width * 0.7), y: Math.round(height / 2) }).up().perform();
408
+ return;
409
+ }
410
+ if (key === 'home') {
411
+ // @ts-ignore wdio global
412
+ if (android) await driver.execute('mobile: pressKey', { keycode: 3 });
413
+ // @ts-ignore wdio global
414
+ else await driver.execute('mobile: pressButton', { name: 'home' });
415
+ return;
416
+ }
417
+ if (key === 'enter') {
418
+ // @ts-ignore wdio global
419
+ if (android) { await driver.execute('mobile: pressKey', { keycode: 66 }); return; }
420
+ await this.typeFocused('\\n');
421
+ return;
422
+ }
423
+ throw new Error('Unsupported key: ' + key);
281
424
  }
282
425
 
283
- async swipe(${p('direction', 'string')}) {
426
+ /** Real window-size-relative swipe. direction is the FINGER direction ('up' drags from bottom to top). */
427
+ async swipe(${p('direction', dirType.slice(2) || 'string')}) {
284
428
  // @ts-ignore wdio global
285
429
  const { width, height } = await driver.getWindowSize();
286
430
  const cx = Math.round(width / 2), cy = Math.round(height / 2);
@@ -290,9 +434,11 @@ export class BaseScreen {
290
434
  left: [Math.round(width * 0.8), cy, Math.round(width * 0.2), cy],
291
435
  right: [Math.round(width * 0.2), cy, Math.round(width * 0.8), cy],
292
436
  };
293
- const [x1, y1, x2, y2] = map[${ts ? 'direction as keyof typeof map' : 'direction'}] || map.up;
437
+ const vec = map[direction];
438
+ if (!vec) throw new Error('Unsupported swipe direction: ' + direction);
439
+ const [x1, y1, x2, y2] = vec;
294
440
  // @ts-ignore wdio global
295
- await driver.action('pointer')
441
+ await driver.action('pointer', { parameters: { pointerType: 'touch' } })
296
442
  .move({ x: x1, y: y1 }).down().pause(100).move({ duration: 600, x: x2, y: y2 }).up().perform();
297
443
  }
298
444
 
@@ -303,9 +449,8 @@ export class BaseScreen {
303
449
  }
304
450
  `;
305
451
  }
306
- /** Per-screen action method name for an (element, action) pair. */
307
- function methodName(action, element) {
308
- const E = pascal(element);
452
+ /** Base (pre-dedupe) action-method name for an (action, element) pair. */
453
+ function methodBase(action, E) {
309
454
  switch (action) {
310
455
  case 'tap':
311
456
  return `tap${E}`;
@@ -316,22 +461,23 @@ function methodName(action, element) {
316
461
  case 'assertVisible':
317
462
  return `assert${E}Visible`;
318
463
  default:
319
- return `act${E}`;
464
+ throw new UnemittableStepError(`cannot emit a ${action} step bound to an element: no generated action exists for it`);
320
465
  }
321
466
  }
322
- function screenClass(screen, steps, ts, t) {
323
- const locImport = ts ? `import type { PlatformLocator } from '../utils/locators.js';\n` : '';
467
+ function screenClass(screen, names, steps, ts) {
324
468
  const lines = [];
325
- lines.push(`// Generated by Swipium. Screen object for ${screen.pageName}${screen.screenSignature ? ` (${screen.screenSignature})` : ''}.`);
469
+ lines.push(`// Generated by Swipium. Screen object for ${commentSafe(screen.pageName)}${screen.screenSignature ? ` (${commentSafe(screen.screenSignature)})` : ''}.`);
326
470
  lines.push('// Selectors are centralized here; tests call the action methods below.');
327
- lines.push(locImport.trimEnd());
471
+ if (ts)
472
+ lines.push(`import type { PlatformLocator } from '../utils/locators.js';`);
328
473
  lines.push(`import { BaseScreen } from './BaseScreen.js';`);
329
474
  lines.push('');
330
- lines.push(`export class ${screen.className} extends BaseScreen {`);
331
- // Locators (centralized).
475
+ lines.push(`export class ${names.cls} extends BaseScreen {`);
476
+ // Locators (centralized). H3: `readonly` + the type annotation are TypeScript-only.
332
477
  for (const el of screen.elements) {
333
- const durabilityNote = el.durability === 'durable' ? '' : ` // ${el.durability} locator${el.remediation ? ` — ${el.remediation}` : ''}`;
334
- lines.push(` readonly ${el.name}${t(': PlatformLocator')} = ${platformLocatorLiteral(el)};${durabilityNote}`);
478
+ const field = names.fields.get(el.name);
479
+ const durabilityNote = el.durability === 'durable' ? '' : ` // ${el.durability} locator${el.remediation ? `: ${commentSafe(el.remediation)}` : ''}`;
480
+ lines.push(` ${ts ? 'readonly ' : ''}${field}${ts ? ': PlatformLocator' : ''} = ${platformLocatorLiteral(el)};${durabilityNote}`);
335
481
  }
336
482
  lines.push('');
337
483
  // Action methods for each (element, action) used in steps on this screen.
@@ -339,47 +485,47 @@ function screenClass(screen, steps, ts, t) {
339
485
  for (const s of steps) {
340
486
  if (s.screen !== screen.className || !s.element)
341
487
  continue;
342
- const el = screen.elements.find((e) => e.name === s.element);
343
- if (!el)
344
- continue;
345
- const name = methodName(s.action, s.element);
346
- if (seen.has(name))
488
+ const key = methodKey(s.action, s.element);
489
+ if (seen.has(key))
347
490
  continue;
348
- seen.add(name);
491
+ seen.add(key);
492
+ const name = names.methods.get(key);
493
+ const field = `this.${names.fields.get(s.element)}`;
349
494
  if (s.action === 'inputText') {
350
495
  lines.push(` async ${name}(${ts ? 'value: string' : 'value'}) {`);
351
- lines.push(` await this.type(this.${s.element}, value);`);
352
- lines.push(' }');
496
+ lines.push(` await this.type(${field}, value);`);
353
497
  }
354
498
  else if (s.action === 'tap') {
355
499
  lines.push(` async ${name}() {`);
356
- lines.push(` await this.tap(this.${s.element});`);
357
- lines.push(' }');
500
+ lines.push(` await this.tap(${field});`);
358
501
  }
359
502
  else if (s.action === 'scrollTo') {
360
- lines.push(` async ${name}() {`);
361
- lines.push(` await this.scrollTo(this.${s.element});`);
362
- lines.push(' }');
503
+ lines.push(` async ${name}(${ts ? "direction: string = 'down'" : "direction = 'down'"}) {`);
504
+ lines.push(` await this.scrollTo(${field}, direction);`);
363
505
  }
364
- else if (s.action === 'assertVisible') {
506
+ else {
365
507
  lines.push(` async ${name}() {`);
366
- lines.push(` await this.assertVisible(this.${s.element});`);
367
- lines.push(' }');
508
+ lines.push(` await this.assertVisible(${field});`);
368
509
  }
510
+ lines.push(' }');
369
511
  }
370
512
  lines.push('}');
371
513
  lines.push('');
372
514
  return lines.join('\n');
373
515
  }
516
+ function envRef(v) {
517
+ return jsProp('process.env', v);
518
+ }
374
519
  function testData(model, ts) {
375
520
  const lines = [];
376
- lines.push('// Generated by Swipium. Test data comes from the ENVIRONMENT — secrets are never inlined.');
521
+ const key = (v) => (isJsIdentifier(varToKey(v)) ? varToKey(v) : JSON.stringify(varToKey(v)));
522
+ lines.push('// Generated by Swipium. Test data comes from the ENVIRONMENT. Secrets are never inlined.');
377
523
  lines.push('export const testData = {');
378
524
  for (const v of model.variables) {
379
- lines.push(` ${varToKey(v)}: process.env.${v} || '',`);
525
+ lines.push(` ${key(v)}: ${envRef(v)} || '',`);
380
526
  }
381
527
  for (const v of model.secrets) {
382
- lines.push(` ${varToKey(v)}: process.env.${v} || '', // secret — provide via environment only`);
528
+ lines.push(` ${key(v)}: ${envRef(v)} || '', // secret, provide via environment only`);
383
529
  }
384
530
  lines.push('};');
385
531
  lines.push('');
@@ -388,61 +534,74 @@ function testData(model, ts) {
388
534
  lines.push('');
389
535
  return lines.join('\n');
390
536
  }
391
- function smokeTest(model, _ts) {
537
+ function smokeTest(model, names) {
392
538
  const classes = [...new Set(model.steps.map((s) => s.screen))];
393
539
  const lines = [];
394
540
  lines.push('// Generated by Swipium. Smoke test driving the recorded flow through the screen objects.');
395
541
  for (const c of classes) {
396
- lines.push(`import { ${c} } from '../src/screens/${c}.js';`);
542
+ const cls = names.get(c).cls;
543
+ lines.push(`import { ${cls} } from '../src/screens/${cls}.js';`);
397
544
  }
398
545
  lines.push(`import { testData } from '../src/data/testData.js';`);
399
546
  lines.push('');
400
- lines.push(`describe('${model.testName} smoke', () => {`);
401
- // instantiate one screen object per class.
402
- const inst = new Map();
403
- for (const c of classes) {
404
- const v = c[0].toLowerCase() + c.slice(1);
405
- inst.set(c, v);
406
- }
407
- lines.push(` it('completes the recorded flow', async () => {`);
408
- for (const [c, v] of inst)
409
- lines.push(` const ${v} = new ${c}();`);
547
+ // H3: titles come from recorded data, so always a JSON-escaped literal, never raw interpolation.
548
+ lines.push(`describe(${JSON.stringify(`${model.testName} smoke`)}, () => {`);
549
+ lines.push(` it(${JSON.stringify('completes the recorded flow')}, async () => {`);
550
+ for (const c of classes)
551
+ lines.push(` const ${names.get(c).instance} = new ${names.get(c).cls}();`);
410
552
  for (const s of model.steps) {
411
- const v = inst.get(s.screen);
412
- lines.push(' ' + stepCall(v, s));
553
+ lines.push(' ' + stepCall(names.get(s.screen), s));
413
554
  }
414
555
  lines.push(' });');
415
556
  lines.push('});');
416
557
  lines.push('');
417
558
  return lines.join('\n');
418
559
  }
419
- function stepCall(screenVar, s) {
560
+ function dataArg(s) {
561
+ return s.varName ? jsProp('testData', varToKey(s.varName)) : JSON.stringify(s.text ?? '');
562
+ }
563
+ function num(n) {
564
+ return Number.isFinite(n) ? Math.round(n) : 0;
565
+ }
566
+ function stepCall(n, s) {
567
+ const v = n.instance;
420
568
  if (s.element) {
421
- const name = methodName(s.action, s.element);
422
- if (s.action === 'inputText') {
423
- const arg = s.varName ? `testData.${varToKey(s.varName)}` : JSON.stringify(s.text ?? '');
424
- return `await ${screenVar}.${name}(${arg});`;
425
- }
426
- return `await ${screenVar}.${name}();`;
569
+ const name = n.methods.get(methodKey(s.action, s.element));
570
+ if (s.action === 'inputText')
571
+ return `await ${v}.${name}(${dataArg(s)});`;
572
+ if (s.action === 'scrollTo')
573
+ return `await ${v}.${name}(${JSON.stringify(checkDirection(s.direction ?? 'down', 'scrollTo step'))});`;
574
+ return `await ${v}.${name}();`;
427
575
  }
428
576
  // No element: generic BaseScreen helpers.
429
577
  switch (s.action) {
430
578
  case 'tapAt':
431
- return `await ${screenVar}.tapAt(${s.coords?.[0] ?? 0}, ${s.coords?.[1] ?? 0}); // coordinate fallback — non-release-grade`;
432
- case 'inputText': {
433
- const arg = s.varName ? `testData.${varToKey(s.varName)}` : JSON.stringify(s.text ?? '');
434
- return `await ${screenVar}.type({ android: '' }, ${arg}); // focused-field input`;
435
- }
579
+ if (!s.coords)
580
+ throw new UnemittableStepError('cannot emit a coordinate tap without coordinates');
581
+ return `await ${v}.tapAt(${num(s.coords[0])}, ${num(s.coords[1])}); // coordinate fallback, non-release-grade`;
582
+ case 'inputText':
583
+ return `await ${v}.typeFocused(${dataArg(s)}); // focused-field input`;
436
584
  case 'press':
437
- return `await ${screenVar}.pressKey(${JSON.stringify(s.key ?? 'back')});`;
585
+ return `await ${v}.pressKey(${JSON.stringify(checkKey(s.key))});`;
438
586
  case 'swipe':
439
- return `await ${screenVar}.swipe(${JSON.stringify(s.direction ?? 'up')});`;
587
+ return `await ${v}.swipe(${JSON.stringify(checkDirection(s.direction ?? 'up', 'swipe step'))});`;
588
+ case 'scrollTo':
589
+ if (!s.text)
590
+ throw new UnemittableStepError('cannot emit a scrollTo step with neither an element nor a target text');
591
+ return `await ${v}.scrollToText(${JSON.stringify(s.text)}, ${JSON.stringify(checkDirection(s.direction ?? 'down', 'scrollTo step'))});`;
440
592
  case 'openUrl':
441
- return `await ${screenVar}.openUrl(${JSON.stringify(s.url ?? '')});`;
593
+ if (!s.url)
594
+ throw new UnemittableStepError('cannot emit an openUrl step without a URL');
595
+ return `await ${v}.openUrl(${JSON.stringify(s.url)});`;
442
596
  case 'assertVisible':
443
- return `await ${screenVar}.assertTextVisible(${JSON.stringify(s.text ?? '')});`;
597
+ if (!s.text)
598
+ throw new UnemittableStepError('cannot emit a text assertion without text');
599
+ return `await ${v}.assertTextVisible(${JSON.stringify(s.text)});`;
600
+ case 'visualCheck':
601
+ // Visual judgement prose is not on-screen text. It's a manual checkpoint, never a failing text check.
602
+ return `// TODO(manual visual check, not automated): ${commentSafe(s.text ?? 'visual checkpoint')}`;
444
603
  default:
445
- return `// unsupported step: ${s.action}`;
604
+ throw new UnemittableStepError(`cannot emit step action ${JSON.stringify(s.action)}: no WebdriverIO equivalent is generated for it`);
446
605
  }
447
606
  }
448
607
  //# sourceMappingURL=jsEmitter.js.map