swipium 1.0.0

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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/appMap/automationLink.js +74 -0
  4. package/dist/appMap/automationLink.js.map +1 -0
  5. package/dist/appMap/build.js +193 -0
  6. package/dist/appMap/build.js.map +1 -0
  7. package/dist/appMap/codeIndex.js +73 -0
  8. package/dist/appMap/codeIndex.js.map +1 -0
  9. package/dist/appMap/featureModel.js +83 -0
  10. package/dist/appMap/featureModel.js.map +1 -0
  11. package/dist/appMap/firstRunApply.js +131 -0
  12. package/dist/appMap/firstRunApply.js.map +1 -0
  13. package/dist/appMap/fsWalk.js +75 -0
  14. package/dist/appMap/fsWalk.js.map +1 -0
  15. package/dist/appMap/issues.js +227 -0
  16. package/dist/appMap/issues.js.map +1 -0
  17. package/dist/appMap/migrations.js +87 -0
  18. package/dist/appMap/migrations.js.map +1 -0
  19. package/dist/appMap/prelaunch.js +66 -0
  20. package/dist/appMap/prelaunch.js.map +1 -0
  21. package/dist/appMap/projectRegistry.js +70 -0
  22. package/dist/appMap/projectRegistry.js.map +1 -0
  23. package/dist/appMap/provenance.js +52 -0
  24. package/dist/appMap/provenance.js.map +1 -0
  25. package/dist/appMap/query.js +118 -0
  26. package/dist/appMap/query.js.map +1 -0
  27. package/dist/appMap/runtimeMerge.js +207 -0
  28. package/dist/appMap/runtimeMerge.js.map +1 -0
  29. package/dist/appMap/schema.js +65 -0
  30. package/dist/appMap/schema.js.map +1 -0
  31. package/dist/appMap/screenMatch.js +75 -0
  32. package/dist/appMap/screenMatch.js.map +1 -0
  33. package/dist/appMap/staticScan.js +614 -0
  34. package/dist/appMap/staticScan.js.map +1 -0
  35. package/dist/appMap/store.js +173 -0
  36. package/dist/appMap/store.js.map +1 -0
  37. package/dist/appMap/tsAstScan.js +184 -0
  38. package/dist/appMap/tsAstScan.js.map +1 -0
  39. package/dist/artifacts/bundletool.js +199 -0
  40. package/dist/artifacts/bundletool.js.map +1 -0
  41. package/dist/artifacts/resolve.js +388 -0
  42. package/dist/artifacts/resolve.js.map +1 -0
  43. package/dist/automationGen/appiumModel.js +129 -0
  44. package/dist/automationGen/appiumModel.js.map +1 -0
  45. package/dist/automationGen/ciEmitter.js +80 -0
  46. package/dist/automationGen/ciEmitter.js.map +1 -0
  47. package/dist/automationGen/jsEmitter.js +440 -0
  48. package/dist/automationGen/jsEmitter.js.map +1 -0
  49. package/dist/automationGen/packagePatch.js +56 -0
  50. package/dist/automationGen/packagePatch.js.map +1 -0
  51. package/dist/automationGen/projectProfile.js +317 -0
  52. package/dist/automationGen/projectProfile.js.map +1 -0
  53. package/dist/automationGen/pythonEmitter.js +386 -0
  54. package/dist/automationGen/pythonEmitter.js.map +1 -0
  55. package/dist/automationGen/readmeEmitter.js +66 -0
  56. package/dist/automationGen/readmeEmitter.js.map +1 -0
  57. package/dist/automationGen/suitePlan.js +94 -0
  58. package/dist/automationGen/suitePlan.js.map +1 -0
  59. package/dist/automationGen/validation.js +150 -0
  60. package/dist/automationGen/validation.js.map +1 -0
  61. package/dist/build/parseBuildLog.js +119 -0
  62. package/dist/build/parseBuildLog.js.map +1 -0
  63. package/dist/build/plan.js +150 -0
  64. package/dist/build/plan.js.map +1 -0
  65. package/dist/ci/preflight.js +85 -0
  66. package/dist/ci/preflight.js.map +1 -0
  67. package/dist/cli/init.js +105 -0
  68. package/dist/cli/init.js.map +1 -0
  69. package/dist/cli/scan.js +85 -0
  70. package/dist/cli/scan.js.map +1 -0
  71. package/dist/cli/suite.js +85 -0
  72. package/dist/cli/suite.js.map +1 -0
  73. package/dist/cli/verify.js +62 -0
  74. package/dist/cli/verify.js.map +1 -0
  75. package/dist/consent/consent.js +43 -0
  76. package/dist/consent/consent.js.map +1 -0
  77. package/dist/context/detect.js +156 -0
  78. package/dist/context/detect.js.map +1 -0
  79. package/dist/context/findApps.js +198 -0
  80. package/dist/context/findApps.js.map +1 -0
  81. package/dist/context/projectRoot.js +41 -0
  82. package/dist/context/projectRoot.js.map +1 -0
  83. package/dist/context/scan.js +167 -0
  84. package/dist/context/scan.js.map +1 -0
  85. package/dist/core/target.js +115 -0
  86. package/dist/core/target.js.map +1 -0
  87. package/dist/core/targetPlan.js +140 -0
  88. package/dist/core/targetPlan.js.map +1 -0
  89. package/dist/drivers/DirectDriver.js +228 -0
  90. package/dist/drivers/DirectDriver.js.map +1 -0
  91. package/dist/drivers/Driver.js +4 -0
  92. package/dist/drivers/Driver.js.map +1 -0
  93. package/dist/drivers/SimctlDriver.js +127 -0
  94. package/dist/drivers/SimctlDriver.js.map +1 -0
  95. package/dist/drivers/WdaDriver.js +250 -0
  96. package/dist/drivers/WdaDriver.js.map +1 -0
  97. package/dist/explore/candidates.js +93 -0
  98. package/dist/explore/candidates.js.map +1 -0
  99. package/dist/explore/graph.js +116 -0
  100. package/dist/explore/graph.js.map +1 -0
  101. package/dist/explore/memory.js +35 -0
  102. package/dist/explore/memory.js.map +1 -0
  103. package/dist/explore/planner.js +105 -0
  104. package/dist/explore/planner.js.map +1 -0
  105. package/dist/explore/policy.js +85 -0
  106. package/dist/explore/policy.js.map +1 -0
  107. package/dist/explore/runner.js +475 -0
  108. package/dist/explore/runner.js.map +1 -0
  109. package/dist/explore/signatures.js +35 -0
  110. package/dist/explore/signatures.js.map +1 -0
  111. package/dist/explore/suite.js +55 -0
  112. package/dist/explore/suite.js.map +1 -0
  113. package/dist/featureTesting/executionBootstrap.js +140 -0
  114. package/dist/featureTesting/executionBootstrap.js.map +1 -0
  115. package/dist/firstRun/authStateMachine.js +83 -0
  116. package/dist/firstRun/authStateMachine.js.map +1 -0
  117. package/dist/firstRun/classifyScreen.js +201 -0
  118. package/dist/firstRun/classifyScreen.js.map +1 -0
  119. package/dist/firstRun/firstRunPlanner.js +207 -0
  120. package/dist/firstRun/firstRunPlanner.js.map +1 -0
  121. package/dist/firstRun/firstRunRunner.js +331 -0
  122. package/dist/firstRun/firstRunRunner.js.map +1 -0
  123. package/dist/firstRun/generatedDataPolicy.js +215 -0
  124. package/dist/firstRun/generatedDataPolicy.js.map +1 -0
  125. package/dist/firstRun/inputPlanner.js +67 -0
  126. package/dist/firstRun/inputPlanner.js.map +1 -0
  127. package/dist/firstRun/onboardingStateMachine.js +46 -0
  128. package/dist/firstRun/onboardingStateMachine.js.map +1 -0
  129. package/dist/firstRun/paywallPolicy.js +54 -0
  130. package/dist/firstRun/paywallPolicy.js.map +1 -0
  131. package/dist/firstRun/types.js +7 -0
  132. package/dist/firstRun/types.js.map +1 -0
  133. package/dist/fixtures/catalog.js +131 -0
  134. package/dist/fixtures/catalog.js.map +1 -0
  135. package/dist/flows/discover.js +18 -0
  136. package/dist/flows/discover.js.map +1 -0
  137. package/dist/flows/generate.js +211 -0
  138. package/dist/flows/generate.js.map +1 -0
  139. package/dist/flows/lint.js +97 -0
  140. package/dist/flows/lint.js.map +1 -0
  141. package/dist/flows/pack.js +68 -0
  142. package/dist/flows/pack.js.map +1 -0
  143. package/dist/flows/run.js +738 -0
  144. package/dist/flows/run.js.map +1 -0
  145. package/dist/flows/schema.js +240 -0
  146. package/dist/flows/schema.js.map +1 -0
  147. package/dist/flows/seedExec.js +108 -0
  148. package/dist/flows/seedExec.js.map +1 -0
  149. package/dist/flows/templates.js +155 -0
  150. package/dist/flows/templates.js.map +1 -0
  151. package/dist/flows/waitGuards.js +12 -0
  152. package/dist/flows/waitGuards.js.map +1 -0
  153. package/dist/index.js +33 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/ios/signing.js +182 -0
  156. package/dist/ios/signing.js.map +1 -0
  157. package/dist/issues/classify.js +186 -0
  158. package/dist/issues/classify.js.map +1 -0
  159. package/dist/issues/fingerprint.js +130 -0
  160. package/dist/issues/fingerprint.js.map +1 -0
  161. package/dist/issues/index.js +240 -0
  162. package/dist/issues/index.js.map +1 -0
  163. package/dist/issues/metrics.js +155 -0
  164. package/dist/issues/metrics.js.map +1 -0
  165. package/dist/issues/recurrence.js +193 -0
  166. package/dist/issues/recurrence.js.map +1 -0
  167. package/dist/issues/report.js +110 -0
  168. package/dist/issues/report.js.map +1 -0
  169. package/dist/issues/reportBridge.js +119 -0
  170. package/dist/issues/reportBridge.js.map +1 -0
  171. package/dist/issues/schema.js +90 -0
  172. package/dist/issues/schema.js.map +1 -0
  173. package/dist/issues/sourceRevision.js +108 -0
  174. package/dist/issues/sourceRevision.js.map +1 -0
  175. package/dist/issues/store.js +155 -0
  176. package/dist/issues/store.js.map +1 -0
  177. package/dist/lib/android.js +278 -0
  178. package/dist/lib/android.js.map +1 -0
  179. package/dist/lib/commandTemplate.js +55 -0
  180. package/dist/lib/commandTemplate.js.map +1 -0
  181. package/dist/lib/coordSpace.js +23 -0
  182. package/dist/lib/coordSpace.js.map +1 -0
  183. package/dist/lib/device.js +87 -0
  184. package/dist/lib/device.js.map +1 -0
  185. package/dist/lib/gitignore.js +22 -0
  186. package/dist/lib/gitignore.js.map +1 -0
  187. package/dist/lib/image.js +97 -0
  188. package/dist/lib/image.js.map +1 -0
  189. package/dist/lib/logger.js +8 -0
  190. package/dist/lib/logger.js.map +1 -0
  191. package/dist/lib/metroState.js +45 -0
  192. package/dist/lib/metroState.js.map +1 -0
  193. package/dist/lib/needsInput.js +201 -0
  194. package/dist/lib/needsInput.js.map +1 -0
  195. package/dist/lib/png.js +103 -0
  196. package/dist/lib/png.js.map +1 -0
  197. package/dist/lib/redact.js +21 -0
  198. package/dist/lib/redact.js.map +1 -0
  199. package/dist/lib/result.js +87 -0
  200. package/dist/lib/result.js.map +1 -0
  201. package/dist/lib/schemaHash.js +65 -0
  202. package/dist/lib/schemaHash.js.map +1 -0
  203. package/dist/lib/sensitive.js +13 -0
  204. package/dist/lib/sensitive.js.map +1 -0
  205. package/dist/lib/simctl.js +149 -0
  206. package/dist/lib/simctl.js.map +1 -0
  207. package/dist/lib/spawn.js +144 -0
  208. package/dist/lib/spawn.js.map +1 -0
  209. package/dist/lib/wda.js +347 -0
  210. package/dist/lib/wda.js.map +1 -0
  211. package/dist/lib/wdaConfig.js +69 -0
  212. package/dist/lib/wdaConfig.js.map +1 -0
  213. package/dist/lib/wdaTune.js +58 -0
  214. package/dist/lib/wdaTune.js.map +1 -0
  215. package/dist/oracle/auth.js +22 -0
  216. package/dist/oracle/auth.js.map +1 -0
  217. package/dist/oracle/failures.js +193 -0
  218. package/dist/oracle/failures.js.map +1 -0
  219. package/dist/oracle/health.js +123 -0
  220. package/dist/oracle/health.js.map +1 -0
  221. package/dist/oracle/record.js +36 -0
  222. package/dist/oracle/record.js.map +1 -0
  223. package/dist/orchestration/envelope.js +52 -0
  224. package/dist/orchestration/envelope.js.map +1 -0
  225. package/dist/orchestration/goal.js +98 -0
  226. package/dist/orchestration/goal.js.map +1 -0
  227. package/dist/plan/plan.js +124 -0
  228. package/dist/plan/plan.js.map +1 -0
  229. package/dist/prompts/index.js +63 -0
  230. package/dist/prompts/index.js.map +1 -0
  231. package/dist/report/artifactManifest.js +44 -0
  232. package/dist/report/artifactManifest.js.map +1 -0
  233. package/dist/report/coverage.js +60 -0
  234. package/dist/report/coverage.js.map +1 -0
  235. package/dist/report/evidence.js +84 -0
  236. package/dist/report/evidence.js.map +1 -0
  237. package/dist/report/export.js +447 -0
  238. package/dist/report/export.js.map +1 -0
  239. package/dist/report/flake.js +61 -0
  240. package/dist/report/flake.js.map +1 -0
  241. package/dist/report/history.js +564 -0
  242. package/dist/report/history.js.map +1 -0
  243. package/dist/report/policy.js +98 -0
  244. package/dist/report/policy.js.map +1 -0
  245. package/dist/report/qaLevel.js +96 -0
  246. package/dist/report/qaLevel.js.map +1 -0
  247. package/dist/report/readiness.js +213 -0
  248. package/dist/report/readiness.js.map +1 -0
  249. package/dist/report/summary.js +42 -0
  250. package/dist/report/summary.js.map +1 -0
  251. package/dist/report/testCatalog.js +93 -0
  252. package/dist/report/testCatalog.js.map +1 -0
  253. package/dist/report/timing.js +37 -0
  254. package/dist/report/timing.js.map +1 -0
  255. package/dist/server.js +180 -0
  256. package/dist/server.js.map +1 -0
  257. package/dist/services/automationGenerate.js +60 -0
  258. package/dist/services/automationGenerate.js.map +1 -0
  259. package/dist/services/build.js +66 -0
  260. package/dist/services/build.js.map +1 -0
  261. package/dist/services/preflight.js +51 -0
  262. package/dist/services/preflight.js.map +1 -0
  263. package/dist/services/prepareAndroid.js +183 -0
  264. package/dist/services/prepareAndroid.js.map +1 -0
  265. package/dist/services/prepareIos.js +162 -0
  266. package/dist/services/prepareIos.js.map +1 -0
  267. package/dist/services/report.js +537 -0
  268. package/dist/services/report.js.map +1 -0
  269. package/dist/services/smoke.js +120 -0
  270. package/dist/services/smoke.js.map +1 -0
  271. package/dist/services/suiteGenerate.js +123 -0
  272. package/dist/services/suiteGenerate.js.map +1 -0
  273. package/dist/services/testSuiteKnowledge.js +150 -0
  274. package/dist/services/testSuiteKnowledge.js.map +1 -0
  275. package/dist/session/attach.js +47 -0
  276. package/dist/session/attach.js.map +1 -0
  277. package/dist/session/progress.js +56 -0
  278. package/dist/session/progress.js.map +1 -0
  279. package/dist/session/store.js +329 -0
  280. package/dist/session/store.js.map +1 -0
  281. package/dist/snapshot/overlays.js +132 -0
  282. package/dist/snapshot/overlays.js.map +1 -0
  283. package/dist/snapshot/parse.js +204 -0
  284. package/dist/snapshot/parse.js.map +1 -0
  285. package/dist/snapshot/present.js +12 -0
  286. package/dist/snapshot/present.js.map +1 -0
  287. package/dist/snapshot/settle.js +36 -0
  288. package/dist/snapshot/settle.js.map +1 -0
  289. package/dist/state/profile.js +318 -0
  290. package/dist/state/profile.js.map +1 -0
  291. package/dist/suite/compile.js +176 -0
  292. package/dist/suite/compile.js.map +1 -0
  293. package/dist/suite/lint.js +45 -0
  294. package/dist/suite/lint.js.map +1 -0
  295. package/dist/suite/pom.js +285 -0
  296. package/dist/suite/pom.js.map +1 -0
  297. package/dist/suite/testcase.js +87 -0
  298. package/dist/suite/testcase.js.map +1 -0
  299. package/dist/testSuite/generator.js +222 -0
  300. package/dist/testSuite/generator.js.map +1 -0
  301. package/dist/testSuite/history.js +44 -0
  302. package/dist/testSuite/history.js.map +1 -0
  303. package/dist/testSuite/issueLinks.js +96 -0
  304. package/dist/testSuite/issueLinks.js.map +1 -0
  305. package/dist/testSuite/merge.js +190 -0
  306. package/dist/testSuite/merge.js.map +1 -0
  307. package/dist/testSuite/schema.js +86 -0
  308. package/dist/testSuite/schema.js.map +1 -0
  309. package/dist/testSuite/store.js +116 -0
  310. package/dist/testSuite/store.js.map +1 -0
  311. package/dist/testSuite/traceability.js +55 -0
  312. package/dist/testSuite/traceability.js.map +1 -0
  313. package/dist/tools/act.js +457 -0
  314. package/dist/tools/act.js.map +1 -0
  315. package/dist/tools/agent.js +225 -0
  316. package/dist/tools/agent.js.map +1 -0
  317. package/dist/tools/appMap.js +317 -0
  318. package/dist/tools/appMap.js.map +1 -0
  319. package/dist/tools/assertVisual.js +74 -0
  320. package/dist/tools/assertVisual.js.map +1 -0
  321. package/dist/tools/automationGenerate.js +394 -0
  322. package/dist/tools/automationGenerate.js.map +1 -0
  323. package/dist/tools/capabilities.js +114 -0
  324. package/dist/tools/capabilities.js.map +1 -0
  325. package/dist/tools/clearOverlay.js +150 -0
  326. package/dist/tools/clearOverlay.js.map +1 -0
  327. package/dist/tools/detectContext.js +41 -0
  328. package/dist/tools/detectContext.js.map +1 -0
  329. package/dist/tools/doctor.js +116 -0
  330. package/dist/tools/doctor.js.map +1 -0
  331. package/dist/tools/explore.js +289 -0
  332. package/dist/tools/explore.js.map +1 -0
  333. package/dist/tools/firstRun.js +136 -0
  334. package/dist/tools/firstRun.js.map +1 -0
  335. package/dist/tools/flow.js +331 -0
  336. package/dist/tools/flow.js.map +1 -0
  337. package/dist/tools/flowGenerate.js +55 -0
  338. package/dist/tools/flowGenerate.js.map +1 -0
  339. package/dist/tools/getArtifact.js +39 -0
  340. package/dist/tools/getArtifact.js.map +1 -0
  341. package/dist/tools/health.js +41 -0
  342. package/dist/tools/health.js.map +1 -0
  343. package/dist/tools/ios.js +492 -0
  344. package/dist/tools/ios.js.map +1 -0
  345. package/dist/tools/jobs.js +20 -0
  346. package/dist/tools/jobs.js.map +1 -0
  347. package/dist/tools/network.js +50 -0
  348. package/dist/tools/network.js.map +1 -0
  349. package/dist/tools/note.js +69 -0
  350. package/dist/tools/note.js.map +1 -0
  351. package/dist/tools/plan.js +49 -0
  352. package/dist/tools/plan.js.map +1 -0
  353. package/dist/tools/prepareIosTarget.js +99 -0
  354. package/dist/tools/prepareIosTarget.js.map +1 -0
  355. package/dist/tools/prepareTarget.js +257 -0
  356. package/dist/tools/prepareTarget.js.map +1 -0
  357. package/dist/tools/report.js +42 -0
  358. package/dist/tools/report.js.map +1 -0
  359. package/dist/tools/screenRecord.js +24 -0
  360. package/dist/tools/screenRecord.js.map +1 -0
  361. package/dist/tools/screenshot.js +63 -0
  362. package/dist/tools/screenshot.js.map +1 -0
  363. package/dist/tools/smoke.js +39 -0
  364. package/dist/tools/smoke.js.map +1 -0
  365. package/dist/tools/snapshot.js +129 -0
  366. package/dist/tools/snapshot.js.map +1 -0
  367. package/dist/tools/startSession.js +169 -0
  368. package/dist/tools/startSession.js.map +1 -0
  369. package/dist/tools/state.js +87 -0
  370. package/dist/tools/state.js.map +1 -0
  371. package/dist/tools/suite.js +412 -0
  372. package/dist/tools/suite.js.map +1 -0
  373. package/dist/tools/testThis.js +774 -0
  374. package/dist/tools/testThis.js.map +1 -0
  375. package/dist/tools/wda.js +477 -0
  376. package/dist/tools/wda.js.map +1 -0
  377. package/dist/version.js +62 -0
  378. package/dist/version.js.map +1 -0
  379. package/dist/visual/ocr.js +72 -0
  380. package/dist/visual/ocr.js.map +1 -0
  381. package/dist/visual/provider.js +75 -0
  382. package/dist/visual/provider.js.map +1 -0
  383. package/docs/README.md +19 -0
  384. package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
  385. package/docs/mcp-server.md +135 -0
  386. package/docs/tools.md +130 -0
  387. package/package.json +70 -0
@@ -0,0 +1,386 @@
1
+ // SWIPIUM-REQ-04 — Python Appium emitter. Pure: turns the shared Appium model into a runnable
2
+ // Python Appium-Python-Client POM suite (pytest when the project uses it, else unittest). POM
3
+ // classes centralize selectors; AppiumBy strategies prefer accessibility id / id; iOS predicate /
4
+ // class-chain only where required; XPath is never emitted. Aligns with the Appium Python quickstart.
5
+ const DEFAULT_TIMEOUT = 15;
6
+ function snake(s) {
7
+ return s
8
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
9
+ .replace(/[^A-Za-z0-9]+/g, '_')
10
+ .replace(/^_+|_+$/g, '')
11
+ .toLowerCase() || 'x';
12
+ }
13
+ /** Env var (SWIPIUM_TEST_PASSWORD) → a stable test_data key (password). */
14
+ export function pyVarToKey(v) {
15
+ const stripped = v.replace(/^SWIPIUM_(TEST_)?/i, '');
16
+ return snake(stripped) || 'value';
17
+ }
18
+ function pyStr(s) {
19
+ return JSON.stringify(s);
20
+ }
21
+ /** (AppiumBy.<X>, "<value>") tuple for one Appium locator. No XPath, ever. */
22
+ export function appiumByTuple(loc) {
23
+ switch (loc.strategy) {
24
+ case 'accessibilityId':
25
+ return `(AppiumBy.ACCESSIBILITY_ID, ${pyStr(loc.value)})`;
26
+ case 'id':
27
+ return `(AppiumBy.ID, ${pyStr(loc.value)})`;
28
+ case 'androidUiautomator':
29
+ return `(AppiumBy.ANDROID_UIAUTOMATOR, ${pyStr(`new UiSelector().text("${loc.value.replace(/"/g, '\\"')}")`)})`;
30
+ case 'name':
31
+ return `(AppiumBy.IOS_PREDICATE, ${pyStr(`name == "${loc.value.replace(/"/g, '\\"')}" OR label == "${loc.value.replace(/"/g, '\\"')}"`)})`;
32
+ case 'iosPredicate':
33
+ return `(AppiumBy.IOS_PREDICATE, ${pyStr(loc.value)})`;
34
+ case 'iosClassChain':
35
+ return `(AppiumBy.IOS_CLASS_CHAIN, ${pyStr(loc.value)})`;
36
+ case 'coordinate':
37
+ return undefined;
38
+ default:
39
+ return undefined;
40
+ }
41
+ }
42
+ function locatorDict(el) {
43
+ const parts = [];
44
+ if (el.android) {
45
+ const t = appiumByTuple(el.android);
46
+ if (t)
47
+ parts.push(`"android": ${t}`);
48
+ }
49
+ if (el.ios) {
50
+ const t = appiumByTuple(el.ios);
51
+ if (t)
52
+ parts.push(`"ios": ${t}`);
53
+ }
54
+ if (el.fallback && el.fallback.strategy === 'coordinate')
55
+ parts.push(`"coordinate": ${pyStr(el.fallback.value)}`);
56
+ else if (el.fallback && !el.android && !el.ios) {
57
+ const t = appiumByTuple(el.fallback);
58
+ if (t)
59
+ parts.push(`"android": ${t}`);
60
+ }
61
+ return `{${parts.join(', ')}}`;
62
+ }
63
+ export function emitPythonSuite(input) {
64
+ const files = [];
65
+ files.push({ path: 'requirements.txt', content: requirementsTxt(input) });
66
+ if (input.framework === 'pytest')
67
+ files.push({ path: 'pytest.ini', content: pytestIni() });
68
+ files.push({ path: 'conftest.py', content: conftest(input) });
69
+ files.push({ path: 'screens/__init__.py', content: '' });
70
+ files.push({ path: 'screens/base_screen.py', content: baseScreen() });
71
+ for (const screen of input.model.screens) {
72
+ files.push({ path: `screens/${snake(screen.className)}.py`, content: screenClass(screen, input.model.steps) });
73
+ }
74
+ files.push({ path: 'data/__init__.py', content: '' });
75
+ files.push({ path: 'data/test_data.py', content: testData(input.model) });
76
+ files.push({ path: 'tests/__init__.py', content: '' });
77
+ files.push({
78
+ path: input.framework === 'pytest' ? 'tests/test_smoke.py' : 'tests/test_smoke.py',
79
+ content: input.framework === 'pytest' ? pytestSmoke(input.model) : unittestSmoke(input.model, input),
80
+ });
81
+ return files;
82
+ }
83
+ function requirementsTxt(input) {
84
+ const lines = ['# Generated by Swipium — review before committing.', 'Appium-Python-Client>=4.0.0', 'selenium>=4.20.0'];
85
+ if (input.framework === 'pytest')
86
+ lines.push('pytest>=8.0.0');
87
+ return lines.join('\n') + '\n';
88
+ }
89
+ function pytestIni() {
90
+ return `# Generated by Swipium.
91
+ [pytest]
92
+ testpaths = tests
93
+ python_files = test_*.py
94
+ addopts = -ra
95
+ `;
96
+ }
97
+ function conftest(input) {
98
+ const appId = input.appId ?? '';
99
+ return `# Generated by Swipium. Appium driver fixture — ALL device/app config is environment-driven.
100
+ # Android UiAutomator2 is the default fast-feedback backend; set SWIPIUM_PLATFORM=ios for XCUITest.
101
+ import os
102
+ import pytest
103
+ from appium import webdriver
104
+ from appium.options.android import UiAutomator2Options
105
+ from appium.options.ios import XCUITestOptions
106
+
107
+
108
+ def build_options():
109
+ platform = os.environ.get("SWIPIUM_PLATFORM", "${input.model.platforms.android ? 'android' : 'ios'}").lower()
110
+ if platform == "ios":
111
+ opts = XCUITestOptions()
112
+ opts.device_name = os.environ.get("IOS_DEVICE_NAME", "iPhone 15")
113
+ bundle_id = os.environ.get("IOS_BUNDLE_ID"${appId ? `, ${pyStr(appId)}` : ''})
114
+ if bundle_id:
115
+ opts.bundle_id = bundle_id
116
+ if os.environ.get("IOS_APP_PATH"):
117
+ opts.app = os.environ["IOS_APP_PATH"]
118
+ if os.environ.get("IOS_UDID"):
119
+ opts.udid = os.environ["IOS_UDID"]
120
+ opts.no_reset = os.environ.get("SWIPIUM_NO_RESET") == "true"
121
+ return opts
122
+ opts = UiAutomator2Options()
123
+ opts.device_name = os.environ.get("ANDROID_DEVICE_NAME", "Android Emulator")
124
+ app_package = os.environ.get("ANDROID_APP_PACKAGE"${appId ? `, ${pyStr(appId)}` : ''})
125
+ if app_package:
126
+ opts.app_package = app_package
127
+ if os.environ.get("ANDROID_APP_ACTIVITY"):
128
+ opts.app_activity = os.environ["ANDROID_APP_ACTIVITY"]
129
+ if os.environ.get("ANDROID_APP_PATH"):
130
+ opts.app = os.environ["ANDROID_APP_PATH"]
131
+ if os.environ.get("ANDROID_UDID"):
132
+ opts.udid = os.environ["ANDROID_UDID"]
133
+ opts.no_reset = os.environ.get("SWIPIUM_NO_RESET") == "true"
134
+ return opts
135
+
136
+
137
+ @pytest.fixture
138
+ def driver():
139
+ url = os.environ.get("APPIUM_URL", "http://127.0.0.1:4723")
140
+ drv = webdriver.Remote(url, options=build_options())
141
+ yield drv
142
+ drv.quit()
143
+ `;
144
+ }
145
+ function baseScreen() {
146
+ return `# Generated by Swipium. BaseScreen centralizes element interaction so selectors resolve
147
+ # per-platform in ONE place and tests never touch raw selectors.
148
+ from appium.webdriver.common.appiumby import AppiumBy # noqa: F401 (used by screen subclasses)
149
+ from selenium.webdriver.support.ui import WebDriverWait
150
+ from selenium.webdriver.support import expected_conditions as EC
151
+
152
+ DEFAULT_TIMEOUT = ${DEFAULT_TIMEOUT}
153
+
154
+
155
+ class BaseScreen:
156
+ def __init__(self, driver):
157
+ self.driver = driver
158
+
159
+ def _spec(self, loc):
160
+ platform = (self.driver.capabilities.get("platformName") or "").lower()
161
+ spec = loc.get("ios") if platform == "ios" else loc.get("android")
162
+ if not spec:
163
+ raise RuntimeError(
164
+ "No durable selector for this platform — element relies on a coordinate fallback "
165
+ "(non-release-grade). Add an accessibility id / resource-id / testID."
166
+ )
167
+ return spec
168
+
169
+ def find(self, loc, timeout=DEFAULT_TIMEOUT):
170
+ by, value = self._spec(loc)
171
+ return WebDriverWait(self.driver, timeout).until(
172
+ EC.presence_of_element_located((by, value))
173
+ )
174
+
175
+ def tap(self, loc):
176
+ self.find(loc).click()
177
+
178
+ def type(self, loc, value):
179
+ el = self.find(loc)
180
+ el.clear()
181
+ el.send_keys(value)
182
+
183
+ def scroll_to(self, loc):
184
+ # Best-effort scroll; Appium resolves visibility on find.
185
+ self.find(loc)
186
+
187
+ def is_visible(self, loc):
188
+ try:
189
+ return self.find(loc).is_displayed()
190
+ except Exception:
191
+ return False
192
+
193
+ def assert_visible(self, loc):
194
+ assert self.find(loc).is_displayed()
195
+
196
+ def assert_text_visible(self, text):
197
+ # Non-release-grade text assertion — prefer a structured locator.
198
+ spec = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textContains("%s")' % text)
199
+ assert WebDriverWait(self.driver, DEFAULT_TIMEOUT).until(
200
+ EC.presence_of_element_located(spec)
201
+ ).is_displayed()
202
+
203
+ def tap_at(self, x, y):
204
+ # Coordinate tap — brittle, non-release-grade fallback.
205
+ self.driver.tap([(x, y)])
206
+
207
+ def press_key(self, key):
208
+ if key == "back":
209
+ self.driver.back()
210
+
211
+ def open_url(self, url):
212
+ self.driver.get(url)
213
+ `;
214
+ }
215
+ function methodName(action, element) {
216
+ const e = snake(element);
217
+ switch (action) {
218
+ case 'tap':
219
+ return `tap_${e}`;
220
+ case 'inputText':
221
+ return `enter_${e}`;
222
+ case 'scrollTo':
223
+ return `scroll_to_${e}`;
224
+ case 'assertVisible':
225
+ return `assert_${e}_visible`;
226
+ default:
227
+ return `act_${e}`;
228
+ }
229
+ }
230
+ function screenClass(screen, steps) {
231
+ const lines = [];
232
+ lines.push(`# Generated by Swipium. Screen object for ${screen.pageName}${screen.screenSignature ? ` (${screen.screenSignature})` : ''}.`);
233
+ lines.push('from appium.webdriver.common.appiumby import AppiumBy');
234
+ lines.push('from .base_screen import BaseScreen');
235
+ lines.push('');
236
+ lines.push('');
237
+ lines.push(`class ${screen.className}(BaseScreen):`);
238
+ if (screen.elements.length === 0)
239
+ lines.push(' pass');
240
+ for (const el of screen.elements) {
241
+ const note = el.durability === 'durable' ? '' : ` # ${el.durability}${el.remediation ? ` — ${el.remediation}` : ''}`;
242
+ lines.push(` ${snake(el.name)} = ${locatorDict(el)}${note}`);
243
+ }
244
+ if (screen.elements.length)
245
+ lines.push('');
246
+ const seen = new Set();
247
+ for (const s of steps) {
248
+ if (s.screen !== screen.className || !s.element)
249
+ continue;
250
+ const el = screen.elements.find((e) => e.name === s.element);
251
+ if (!el)
252
+ continue;
253
+ const name = methodName(s.action, s.element);
254
+ if (seen.has(name))
255
+ continue;
256
+ seen.add(name);
257
+ const attr = snake(s.element);
258
+ if (s.action === 'inputText') {
259
+ lines.push(` def ${name}(self, value):`);
260
+ lines.push(` self.type(self.${attr}, value)`);
261
+ lines.push('');
262
+ }
263
+ else if (s.action === 'tap') {
264
+ lines.push(` def ${name}(self):`);
265
+ lines.push(` self.tap(self.${attr})`);
266
+ lines.push('');
267
+ }
268
+ else if (s.action === 'scrollTo') {
269
+ lines.push(` def ${name}(self):`);
270
+ lines.push(` self.scroll_to(self.${attr})`);
271
+ lines.push('');
272
+ }
273
+ else if (s.action === 'assertVisible') {
274
+ lines.push(` def ${name}(self):`);
275
+ lines.push(` self.assert_visible(self.${attr})`);
276
+ lines.push('');
277
+ }
278
+ }
279
+ return lines.join('\n').replace(/\n+$/, '\n');
280
+ }
281
+ function testData(model) {
282
+ const lines = [];
283
+ lines.push('# Generated by Swipium. Test data comes from the ENVIRONMENT — secrets are never inlined.');
284
+ lines.push('import os');
285
+ lines.push('');
286
+ lines.push('test_data = {');
287
+ for (const v of model.variables)
288
+ lines.push(` ${pyStr(pyVarToKey(v))}: os.environ.get(${pyStr(v)}, ""),`);
289
+ for (const v of model.secrets)
290
+ lines.push(` ${pyStr(pyVarToKey(v))}: os.environ.get(${pyStr(v)}, ""), # secret — environment only`);
291
+ lines.push('}');
292
+ return lines.join('\n') + '\n';
293
+ }
294
+ function importsForTest(model) {
295
+ const classes = [...new Set(model.steps.map((s) => s.screen))];
296
+ return classes.map((c) => `from screens.${snake(c)} import ${c}`);
297
+ }
298
+ function stepCall(screenVar, s) {
299
+ if (s.element) {
300
+ const name = methodName(s.action, s.element);
301
+ if (s.action === 'inputText') {
302
+ const arg = s.varName ? `test_data[${pyStr(pyVarToKey(s.varName))}]` : pyStr(s.text ?? '');
303
+ return `${screenVar}.${name}(${arg})`;
304
+ }
305
+ return `${screenVar}.${name}()`;
306
+ }
307
+ switch (s.action) {
308
+ case 'tapAt':
309
+ return `${screenVar}.tap_at(${s.coords?.[0] ?? 0}, ${s.coords?.[1] ?? 0}) # coordinate fallback — non-release-grade`;
310
+ case 'inputText': {
311
+ const arg = s.varName ? `test_data[${pyStr(pyVarToKey(s.varName))}]` : pyStr(s.text ?? '');
312
+ return `${screenVar}.type({"android": (AppiumBy.ACCESSIBILITY_ID, "")}, ${arg}) # focused-field input`;
313
+ }
314
+ case 'press':
315
+ return `${screenVar}.press_key(${pyStr(s.key ?? 'back')})`;
316
+ case 'swipe':
317
+ return `${screenVar}.driver.swipe(0, 0, 0, 0) # swipe ${s.direction ?? 'up'} — adjust coordinates`;
318
+ case 'openUrl':
319
+ return `${screenVar}.open_url(${pyStr(s.url ?? '')})`;
320
+ case 'assertVisible':
321
+ return `${screenVar}.assert_text_visible(${pyStr(s.text ?? '')})`;
322
+ default:
323
+ return `pass # unsupported step: ${s.action}`;
324
+ }
325
+ }
326
+ function instanceVars(model) {
327
+ const classes = [...new Set(model.steps.map((s) => s.screen))];
328
+ const m = new Map();
329
+ for (const c of classes)
330
+ m.set(c, snake(c));
331
+ return m;
332
+ }
333
+ function pytestSmoke(model) {
334
+ const lines = [];
335
+ lines.push('# Generated by Swipium. Smoke test driving the recorded flow through the screen objects.');
336
+ lines.push(...importsForTest(model));
337
+ lines.push('from data.test_data import test_data # noqa: F401');
338
+ const usesFocused = model.steps.some((s) => !s.element && s.action === 'inputText');
339
+ if (usesFocused)
340
+ lines.push('from appium.webdriver.common.appiumby import AppiumBy # noqa: F401');
341
+ lines.push('');
342
+ lines.push('');
343
+ lines.push('def test_smoke(driver):');
344
+ const inst = instanceVars(model);
345
+ for (const [c, v] of inst)
346
+ lines.push(` ${v} = ${c}(driver)`);
347
+ for (const s of model.steps)
348
+ lines.push(` ${stepCall(inst.get(s.screen), s)}`);
349
+ return lines.join('\n') + '\n';
350
+ }
351
+ function unittestSmoke(model, input) {
352
+ const lines = [];
353
+ lines.push('# Generated by Swipium. Smoke test (unittest) driving the recorded flow through screen objects.');
354
+ lines.push('import os');
355
+ lines.push('import unittest');
356
+ lines.push('from appium import webdriver');
357
+ lines.push('from conftest import build_options');
358
+ lines.push(...importsForTest(model));
359
+ lines.push('from data.test_data import test_data # noqa: F401');
360
+ const usesFocused = model.steps.some((s) => !s.element && s.action === 'inputText');
361
+ if (usesFocused)
362
+ lines.push('from appium.webdriver.common.appiumby import AppiumBy # noqa: F401');
363
+ lines.push('');
364
+ lines.push('');
365
+ lines.push('class SmokeTest(unittest.TestCase):');
366
+ lines.push(' def setUp(self):');
367
+ lines.push(' url = os.environ.get("APPIUM_URL", "http://127.0.0.1:4723")');
368
+ lines.push(' self.driver = webdriver.Remote(url, options=build_options())');
369
+ lines.push('');
370
+ lines.push(' def tearDown(self):');
371
+ lines.push(' if self.driver:');
372
+ lines.push(' self.driver.quit()');
373
+ lines.push('');
374
+ lines.push(' def test_smoke(self):');
375
+ const inst = instanceVars(model);
376
+ for (const [c, v] of inst)
377
+ lines.push(` ${v} = ${c}(self.driver)`);
378
+ for (const s of model.steps)
379
+ lines.push(` ${stepCall(inst.get(s.screen), s)}`);
380
+ lines.push('');
381
+ lines.push('');
382
+ lines.push('if __name__ == "__main__":');
383
+ lines.push(' unittest.main()');
384
+ return lines.join('\n') + '\n';
385
+ }
386
+ //# sourceMappingURL=pythonEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pythonEmitter.js","sourceRoot":"","sources":["../../src/automationGen/pythonEmitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ // SWIPIUM-REQ-04 — README emitter. Pure: documents the generated suite, the required environment
2
+ // variables (app id/path, device, Appium host/port, credentials, test data), and the exact run
3
+ // commands. Honest about platform coverage and non-release-grade fallbacks.
4
+ function envTable(model, isPython) {
5
+ const common = [
6
+ '| `APPIUM_HOST` / `APPIUM_PORT`' + (isPython ? ' / `APPIUM_URL`' : '') + ' | Appium server location (default 127.0.0.1:4723) |',
7
+ '| `SWIPIUM_PLATFORM` | `android` (default) or `ios` |',
8
+ '| `ANDROID_DEVICE_NAME`, `ANDROID_APP_PACKAGE`, `ANDROID_APP_ACTIVITY`, `ANDROID_APP_PATH`, `ANDROID_UDID` | Android target/app |',
9
+ '| `IOS_DEVICE_NAME`, `IOS_BUNDLE_ID`, `IOS_APP_PATH`, `IOS_UDID` | iOS target/app (when SWIPIUM_PLATFORM=ios) |',
10
+ ];
11
+ const data = model.variables.map((v) => `| \`${v}\` | test data (non-secret) |`);
12
+ const secrets = model.secrets.map((v) => `| \`${v}\` | **secret** — provide via environment/CI secrets only |`);
13
+ return ['| Variable | Purpose |', '| --- | --- |', ...common, ...data, ...secrets];
14
+ }
15
+ export function emitReadme(input) {
16
+ const isPython = input.language === 'python';
17
+ const { profile, model } = input;
18
+ const platformCoverage = [];
19
+ if (model.platforms.android)
20
+ platformCoverage.push(`Android (${profile.platforms.android.level})`);
21
+ if (model.platforms.ios)
22
+ platformCoverage.push(`iOS (${profile.platforms.ios.level})`);
23
+ const runCmd = isPython
24
+ ? profile.testFramework === 'pytest'
25
+ ? '```sh\npip install -r requirements.txt\nappium & # start a local Appium server\npytest\n```'
26
+ : '```sh\npip install -r requirements.txt\nappium & # start a local Appium server\npython -m unittest discover -s tests\n```'
27
+ : '```sh\nnpm install\nnpx appium & # or rely on the @wdio/appium-service\nnpm test\n```';
28
+ const brittle = model.audit.brittle;
29
+ const lines = [];
30
+ lines.push(`# ${input.appId ?? 'App'} — Appium ${isPython ? 'Python' : 'WebdriverIO'} POM suite`);
31
+ lines.push('');
32
+ lines.push('> Generated by Swipium from recorded QA actions. **Review before committing.**');
33
+ lines.push('');
34
+ lines.push('## What this is');
35
+ lines.push('');
36
+ lines.push(`A Page/Screen Object Model Appium suite (${input.language}). Selectors live in screen objects; tests call action methods only.`);
37
+ lines.push('');
38
+ lines.push(`- **Language:** ${input.language}`);
39
+ lines.push(`- **Runner:** ${profile.testFramework}`);
40
+ lines.push(`- **Default backend:** ${profile.defaultBackend}${profile.secondaryBackend ? ` (secondary: ${profile.secondaryBackend})` : ''}`);
41
+ lines.push(`- **Platform coverage in this suite:** ${platformCoverage.join(', ') || 'none detected'}`);
42
+ lines.push(`- **Screens:** ${model.screens.map((s) => s.className).join(', ') || 'none'}`);
43
+ lines.push('');
44
+ lines.push('## Run');
45
+ lines.push('');
46
+ lines.push(runCmd);
47
+ lines.push('');
48
+ lines.push('## Environment variables');
49
+ lines.push('');
50
+ lines.push(...envTable(model, isPython));
51
+ lines.push('');
52
+ lines.push('## Locator readiness');
53
+ lines.push('');
54
+ lines.push(`Locator durability: ${model.audit.durable} durable / ${model.audit.semi} semi / ${brittle} brittle (${model.audit.brittlePct}% brittle).`);
55
+ if (brittle > 0) {
56
+ lines.push('');
57
+ lines.push(`⚠ ${brittle} brittle/coordinate locator(s) are marked non-release-grade in the screen objects. Add a durable accessibility id / resource-id / testID before gating CI on this suite.`);
58
+ }
59
+ lines.push('');
60
+ lines.push('## Honest coverage note');
61
+ lines.push('');
62
+ lines.push('iOS selectors/capabilities are emitted from app-map evidence where available, but iOS coverage is NOT proven unless the suite was actually run on iOS. XPath is never generated.');
63
+ lines.push('');
64
+ return lines.join('\n');
65
+ }
66
+ //# sourceMappingURL=readmeEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readmeEmitter.js","sourceRoot":"","sources":["../../src/automationGen/readmeEmitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ // SWIPIUM-REQ-04 — suite-generation plan. Pure: assembles the read-only plan behind
2
+ // qa_automation_plan from the project profile + (optional) Appium model. No device, no writes.
3
+ // Honest about prerequisites (map/recorded actions) and locator readiness.
4
+ import { emitJsSuite } from './jsEmitter.js';
5
+ import { emitPythonSuite } from './pythonEmitter.js';
6
+ /** .swipium/automation/<dir> — js for TS/JS, python for Python (matches REQ-04 layout). */
7
+ export function outputDirFor(language) {
8
+ return `.swipium/automation/${language === 'python' ? 'python' : 'js'}`;
9
+ }
10
+ function readinessFromPct(brittlePct, hasActions) {
11
+ if (!hasActions)
12
+ return 'unknown';
13
+ if (brittlePct === 0)
14
+ return 'durable';
15
+ if (brittlePct < 40)
16
+ return 'mixed';
17
+ return 'brittle';
18
+ }
19
+ export function buildSuitePlan(profile, opts = {}) {
20
+ const language = profile.automationLanguage;
21
+ const outputDir = outputDirFor(language);
22
+ const platforms = { android: profile.platforms.android.level !== 'none', ios: profile.platforms.ios.level !== 'none' };
23
+ const blockers = [];
24
+ const prerequisites = [];
25
+ const hasActions = !!opts.model && opts.model.steps.length > 0;
26
+ const actionCount = opts.model ? opts.model.steps.length : opts.actionCount ?? 0;
27
+ let mapCoverage = null;
28
+ let filesPlanned = [];
29
+ if (opts.model) {
30
+ const a = opts.model.audit;
31
+ mapCoverage = {
32
+ hasActions,
33
+ actionCount,
34
+ screenCount: opts.model.screens.length,
35
+ durable: a.durable,
36
+ semi: a.semi,
37
+ brittle: a.brittle,
38
+ brittlePct: a.brittlePct,
39
+ };
40
+ const files = language === 'python'
41
+ ? emitPythonSuite({ model: opts.model, profile, appId: opts.appId, framework: profile.testFramework === 'pytest' ? 'pytest' : 'unittest' })
42
+ : emitJsSuite({ model: opts.model, profile, appId: opts.appId, language });
43
+ filesPlanned = files.map((f) => `${outputDir}/${f.path}`);
44
+ filesPlanned.push(`${outputDir}/README.md`);
45
+ if (opts.includeCi)
46
+ filesPlanned.push(`${outputDir}/ci.example.yml`);
47
+ }
48
+ else {
49
+ // No model yet — list the skeleton we WOULD generate, and require a recording/map pass first.
50
+ blockers.push({
51
+ code: 'NO_RECORDED_ACTIONS',
52
+ detail: 'No recorded actions / app map to turn into a POM suite.',
53
+ nextStep: 'Run qa_test_this { goal: "create_automation_suite" } (smoke + explore records actions), or qa_explore to build the app map, then re-run qa_automation_generate.',
54
+ });
55
+ prerequisites.push('Record actions via qa_test_this/qa_smoke/qa_explore, or build the app map first.');
56
+ }
57
+ if (!platforms.android && !platforms.ios) {
58
+ blockers.push({
59
+ code: 'NO_PLATFORM_SUPPORT',
60
+ detail: 'Neither Android nor iOS support was detected for this project.',
61
+ nextStep: 'Pass platform=android|ios|both, or point projectRoot at the mobile app target.',
62
+ });
63
+ }
64
+ if (!opts.mapPresent && !opts.model) {
65
+ prerequisites.push('Build/refresh the app map (qa_explore) for cross-platform screen evidence.');
66
+ }
67
+ const locatorReadiness = readinessFromPct(mapCoverage?.brittlePct ?? 0, hasActions);
68
+ if (mapCoverage && mapCoverage.brittle > 0) {
69
+ blockers.push({
70
+ code: 'BRITTLE_LOCATORS',
71
+ detail: `${mapCoverage.brittle} brittle/coordinate locator(s) (${mapCoverage.brittlePct}% brittle) — not release-grade.`,
72
+ nextStep: 'Add durable accessibility id / resource-id / testID; generated suite marks these as candidate-only.',
73
+ });
74
+ }
75
+ const nextAction = blockers.some((b) => b.code === 'NO_RECORDED_ACTIONS')
76
+ ? 'qa_test_this { goal: "create_automation_suite" }'
77
+ : blockers.some((b) => b.code === 'NO_PLATFORM_SUPPORT')
78
+ ? 'qa_automation_plan { platform: "android" }'
79
+ : 'qa_automation_generate { save: true }';
80
+ return {
81
+ profile,
82
+ language,
83
+ outputDir,
84
+ platforms,
85
+ backends: { default: profile.defaultBackend, secondary: profile.secondaryBackend },
86
+ mapCoverage,
87
+ prerequisites,
88
+ filesPlanned,
89
+ blockers,
90
+ locatorReadiness,
91
+ nextAction,
92
+ };
93
+ }
94
+ //# sourceMappingURL=suitePlan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suitePlan.js","sourceRoot":"","sources":["../../src/automationGen/suitePlan.ts"],"names":[],"mappings":"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"}