@monoes/monobrowse 1.0.11 → 1.0.13

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 (380) hide show
  1. package/dist/src/__tests__/adapters.test.js +5 -2
  2. package/dist/src/__tests__/adapters.test.js.map +1 -1
  3. package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
  4. package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
  5. package/dist/src/__tests__/box-model.test.js +9 -5
  6. package/dist/src/__tests__/box-model.test.js.map +1 -1
  7. package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
  8. package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
  9. package/dist/src/__tests__/browser-launch.test.js +17 -10
  10. package/dist/src/__tests__/browser-launch.test.js.map +1 -1
  11. package/dist/src/__tests__/cdp-client.test.js +9 -3
  12. package/dist/src/__tests__/cdp-client.test.js.map +1 -1
  13. package/dist/src/__tests__/close-browser.test.d.ts +13 -0
  14. package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
  15. package/dist/src/__tests__/close-browser.test.js +5 -5
  16. package/dist/src/__tests__/close-browser.test.js.map +1 -1
  17. package/dist/src/__tests__/console-log.test.js +17 -6
  18. package/dist/src/__tests__/console-log.test.js.map +1 -1
  19. package/dist/src/__tests__/find.test.js +26 -6
  20. package/dist/src/__tests__/find.test.js.map +1 -1
  21. package/dist/src/__tests__/frame-command.test.js +9 -3
  22. package/dist/src/__tests__/frame-command.test.js.map +1 -1
  23. package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
  24. package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
  25. package/dist/src/__tests__/output.test.js +1 -1
  26. package/dist/src/__tests__/output.test.js.map +1 -1
  27. package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
  28. package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
  29. package/dist/src/__tests__/profiler-heap.test.js +154 -0
  30. package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
  31. package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
  32. package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
  33. package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
  34. package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
  35. package/dist/src/__tests__/ref-cache.test.js +18 -10
  36. package/dist/src/__tests__/ref-cache.test.js.map +1 -1
  37. package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
  38. package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
  39. package/dist/src/__tests__/report-a11y.test.js +147 -0
  40. package/dist/src/__tests__/report-a11y.test.js.map +1 -0
  41. package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
  42. package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
  43. package/dist/src/__tests__/report-analyze.test.js +157 -0
  44. package/dist/src/__tests__/report-analyze.test.js.map +1 -0
  45. package/dist/src/__tests__/report-budget.test.d.ts +2 -0
  46. package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
  47. package/dist/src/__tests__/report-budget.test.js +80 -0
  48. package/dist/src/__tests__/report-budget.test.js.map +1 -0
  49. package/dist/src/__tests__/report-diff.test.d.ts +2 -0
  50. package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
  51. package/dist/src/__tests__/report-diff.test.js +231 -0
  52. package/dist/src/__tests__/report-diff.test.js.map +1 -0
  53. package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
  54. package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
  55. package/dist/src/__tests__/report-evidence.test.js +214 -0
  56. package/dist/src/__tests__/report-evidence.test.js.map +1 -0
  57. package/dist/src/__tests__/report-flake.test.d.ts +2 -0
  58. package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
  59. package/dist/src/__tests__/report-flake.test.js +182 -0
  60. package/dist/src/__tests__/report-flake.test.js.map +1 -0
  61. package/dist/src/__tests__/report-history.test.d.ts +2 -0
  62. package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
  63. package/dist/src/__tests__/report-history.test.js +229 -0
  64. package/dist/src/__tests__/report-history.test.js.map +1 -0
  65. package/dist/src/__tests__/report-output.test.d.ts +2 -0
  66. package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
  67. package/dist/src/__tests__/report-output.test.js +169 -0
  68. package/dist/src/__tests__/report-output.test.js.map +1 -0
  69. package/dist/src/__tests__/report-png.test.d.ts +2 -0
  70. package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
  71. package/dist/src/__tests__/report-png.test.js +84 -0
  72. package/dist/src/__tests__/report-png.test.js.map +1 -0
  73. package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
  74. package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
  75. package/dist/src/__tests__/report-render-extras.test.js +285 -0
  76. package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
  77. package/dist/src/__tests__/report-render.test.d.ts +2 -0
  78. package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
  79. package/dist/src/__tests__/report-render.test.js +143 -0
  80. package/dist/src/__tests__/report-render.test.js.map +1 -0
  81. package/dist/src/__tests__/report-run.test.d.ts +2 -0
  82. package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
  83. package/dist/src/__tests__/report-run.test.js +234 -0
  84. package/dist/src/__tests__/report-run.test.js.map +1 -0
  85. package/dist/src/__tests__/session-state.test.d.ts +8 -0
  86. package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
  87. package/dist/src/__tests__/session-state.test.js +10 -10
  88. package/dist/src/__tests__/session-state.test.js.map +1 -1
  89. package/dist/src/__tests__/snapshot.test.js +44 -14
  90. package/dist/src/__tests__/snapshot.test.js.map +1 -1
  91. package/dist/src/__tests__/storage-eval.test.js +14 -6
  92. package/dist/src/__tests__/storage-eval.test.js.map +1 -1
  93. package/dist/src/__tests__/tabs.test.js +25 -9
  94. package/dist/src/__tests__/tabs.test.js.map +1 -1
  95. package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
  96. package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
  97. package/dist/src/browser/action-builder/analyzer.js +25 -9
  98. package/dist/src/browser/action-builder/analyzer.js.map +1 -1
  99. package/dist/src/browser/action-builder/types.d.ts.map +1 -1
  100. package/dist/src/browser/actions.d.ts +1 -1
  101. package/dist/src/browser/actions.d.ts.map +1 -1
  102. package/dist/src/browser/actions.js +16 -6
  103. package/dist/src/browser/actions.js.map +1 -1
  104. package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
  105. package/dist/src/browser/adapters/gemini.js.map +1 -1
  106. package/dist/src/browser/adapters/google.d.ts.map +1 -1
  107. package/dist/src/browser/adapters/google.js.map +1 -1
  108. package/dist/src/browser/adapters/index.d.ts.map +1 -1
  109. package/dist/src/browser/adapters/index.js +3 -3
  110. package/dist/src/browser/adapters/index.js.map +1 -1
  111. package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
  112. package/dist/src/browser/adapters/instagram.js.map +1 -1
  113. package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
  114. package/dist/src/browser/adapters/linkedin.js.map +1 -1
  115. package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
  116. package/dist/src/browser/adapters/microsoft.js.map +1 -1
  117. package/dist/src/browser/adapters/x.d.ts.map +1 -1
  118. package/dist/src/browser/adapters/x.js.map +1 -1
  119. package/dist/src/browser/browser.d.ts +30 -0
  120. package/dist/src/browser/browser.d.ts.map +1 -1
  121. package/dist/src/browser/browser.js +122 -15
  122. package/dist/src/browser/browser.js.map +1 -1
  123. package/dist/src/browser/cdp.d.ts.map +1 -1
  124. package/dist/src/browser/cdp.js +21 -8
  125. package/dist/src/browser/cdp.js.map +1 -1
  126. package/dist/src/browser/console-log.d.ts.map +1 -1
  127. package/dist/src/browser/console-log.js +2 -2
  128. package/dist/src/browser/console-log.js.map +1 -1
  129. package/dist/src/browser/dashboard/server.d.ts.map +1 -1
  130. package/dist/src/browser/dashboard/server.js +29 -19
  131. package/dist/src/browser/dashboard/server.js.map +1 -1
  132. package/dist/src/browser/dashboard/ui.html +153 -165
  133. package/dist/src/browser/dialog.d.ts.map +1 -1
  134. package/dist/src/browser/dialog.js +3 -1
  135. package/dist/src/browser/dialog.js.map +1 -1
  136. package/dist/src/browser/emulation.d.ts.map +1 -1
  137. package/dist/src/browser/emulation.js +21 -6
  138. package/dist/src/browser/emulation.js.map +1 -1
  139. package/dist/src/browser/find.d.ts +4 -4
  140. package/dist/src/browser/find.d.ts.map +1 -1
  141. package/dist/src/browser/find.js +14 -6
  142. package/dist/src/browser/find.js.map +1 -1
  143. package/dist/src/browser/har.d.ts.map +1 -1
  144. package/dist/src/browser/har.js +14 -7
  145. package/dist/src/browser/har.js.map +1 -1
  146. package/dist/src/browser/index.d.ts +17 -16
  147. package/dist/src/browser/index.d.ts.map +1 -1
  148. package/dist/src/browser/index.js +17 -16
  149. package/dist/src/browser/index.js.map +1 -1
  150. package/dist/src/browser/network.d.ts.map +1 -1
  151. package/dist/src/browser/network.js +14 -4
  152. package/dist/src/browser/network.js.map +1 -1
  153. package/dist/src/browser/pdf.d.ts.map +1 -1
  154. package/dist/src/browser/pdf.js +3 -3
  155. package/dist/src/browser/pdf.js.map +1 -1
  156. package/dist/src/browser/profiler.d.ts.map +1 -1
  157. package/dist/src/browser/profiler.js +22 -20
  158. package/dist/src/browser/profiler.js.map +1 -1
  159. package/dist/src/browser/record.d.ts +1 -1
  160. package/dist/src/browser/record.d.ts.map +1 -1
  161. package/dist/src/browser/record.js +18 -7
  162. package/dist/src/browser/record.js.map +1 -1
  163. package/dist/src/browser/ref-cache.d.ts.map +1 -1
  164. package/dist/src/browser/ref-cache.js +9 -4
  165. package/dist/src/browser/ref-cache.js.map +1 -1
  166. package/dist/src/browser/screenshot.d.ts.map +1 -1
  167. package/dist/src/browser/screenshot.js +11 -7
  168. package/dist/src/browser/screenshot.js.map +1 -1
  169. package/dist/src/browser/session.d.ts +1 -1
  170. package/dist/src/browser/session.d.ts.map +1 -1
  171. package/dist/src/browser/session.js +27 -8
  172. package/dist/src/browser/session.js.map +1 -1
  173. package/dist/src/browser/snapshot.d.ts +1 -1
  174. package/dist/src/browser/snapshot.d.ts.map +1 -1
  175. package/dist/src/browser/snapshot.js +8 -4
  176. package/dist/src/browser/snapshot.js.map +1 -1
  177. package/dist/src/browser/storage.d.ts.map +1 -1
  178. package/dist/src/browser/storage.js.map +1 -1
  179. package/dist/src/browser/tabs.d.ts.map +1 -1
  180. package/dist/src/browser/tabs.js +9 -3
  181. package/dist/src/browser/tabs.js.map +1 -1
  182. package/dist/src/browser/trace.d.ts.map +1 -1
  183. package/dist/src/browser/trace.js +3 -3
  184. package/dist/src/browser/trace.js.map +1 -1
  185. package/dist/src/browser/types.d.ts.map +1 -1
  186. package/dist/src/browser/types.js +23 -4
  187. package/dist/src/browser/types.js.map +1 -1
  188. package/dist/src/browser/vitals.d.ts.map +1 -1
  189. package/dist/src/browser/vitals.js +1 -1
  190. package/dist/src/browser/vitals.js.map +1 -1
  191. package/dist/src/browser/wait.d.ts.map +1 -1
  192. package/dist/src/browser/wait.js +11 -5
  193. package/dist/src/browser/wait.js.map +1 -1
  194. package/dist/src/cli/action.d.ts.map +1 -1
  195. package/dist/src/cli/action.js +14 -11
  196. package/dist/src/cli/action.js.map +1 -1
  197. package/dist/src/cli/commands.d.ts.map +1 -1
  198. package/dist/src/cli/commands.js +707 -159
  199. package/dist/src/cli/commands.js.map +1 -1
  200. package/dist/src/cli/output.js +5 -5
  201. package/dist/src/cli/output.js.map +1 -1
  202. package/dist/src/cli/platform.d.ts.map +1 -1
  203. package/dist/src/cli/platform.js +15 -11
  204. package/dist/src/cli/platform.js.map +1 -1
  205. package/dist/src/cli/types.d.ts +1 -1
  206. package/dist/src/cli/types.d.ts.map +1 -1
  207. package/dist/src/cli.js +21 -9
  208. package/dist/src/cli.js.map +1 -1
  209. package/dist/src/index.d.ts +2 -2
  210. package/dist/src/index.d.ts.map +1 -1
  211. package/dist/src/index.js +2 -2
  212. package/dist/src/index.js.map +1 -1
  213. package/dist/src/report/a11y.d.ts +52 -0
  214. package/dist/src/report/a11y.d.ts.map +1 -0
  215. package/dist/src/report/a11y.js +231 -0
  216. package/dist/src/report/a11y.js.map +1 -0
  217. package/dist/src/report/analyze.d.ts +20 -0
  218. package/dist/src/report/analyze.d.ts.map +1 -0
  219. package/dist/src/report/analyze.js +136 -0
  220. package/dist/src/report/analyze.js.map +1 -0
  221. package/dist/src/report/budget.d.ts +27 -0
  222. package/dist/src/report/budget.d.ts.map +1 -0
  223. package/dist/src/report/budget.js +143 -0
  224. package/dist/src/report/budget.js.map +1 -0
  225. package/dist/src/report/collect-a11y.d.ts +25 -0
  226. package/dist/src/report/collect-a11y.d.ts.map +1 -0
  227. package/dist/src/report/collect-a11y.js +154 -0
  228. package/dist/src/report/collect-a11y.js.map +1 -0
  229. package/dist/src/report/collect.d.ts +45 -0
  230. package/dist/src/report/collect.d.ts.map +1 -0
  231. package/dist/src/report/collect.js +275 -0
  232. package/dist/src/report/collect.js.map +1 -0
  233. package/dist/src/report/evidence.d.ts +80 -0
  234. package/dist/src/report/evidence.d.ts.map +1 -0
  235. package/dist/src/report/evidence.js +279 -0
  236. package/dist/src/report/evidence.js.map +1 -0
  237. package/dist/src/report/flake.d.ts +88 -0
  238. package/dist/src/report/flake.d.ts.map +1 -0
  239. package/dist/src/report/flake.js +232 -0
  240. package/dist/src/report/flake.js.map +1 -0
  241. package/dist/src/report/history.d.ts +85 -0
  242. package/dist/src/report/history.d.ts.map +1 -0
  243. package/dist/src/report/history.js +176 -0
  244. package/dist/src/report/history.js.map +1 -0
  245. package/dist/src/report/index.d.ts +102 -0
  246. package/dist/src/report/index.d.ts.map +1 -0
  247. package/dist/src/report/index.js +216 -0
  248. package/dist/src/report/index.js.map +1 -0
  249. package/dist/src/report/pixel-diff.d.ts +30 -0
  250. package/dist/src/report/pixel-diff.d.ts.map +1 -0
  251. package/dist/src/report/pixel-diff.js +175 -0
  252. package/dist/src/report/pixel-diff.js.map +1 -0
  253. package/dist/src/report/png.d.ts +28 -0
  254. package/dist/src/report/png.d.ts.map +1 -0
  255. package/dist/src/report/png.js +259 -0
  256. package/dist/src/report/png.js.map +1 -0
  257. package/dist/src/report/render-evidence.d.ts +16 -0
  258. package/dist/src/report/render-evidence.d.ts.map +1 -0
  259. package/dist/src/report/render-evidence.js +174 -0
  260. package/dist/src/report/render-evidence.js.map +1 -0
  261. package/dist/src/report/render-trend.d.ts +16 -0
  262. package/dist/src/report/render-trend.d.ts.map +1 -0
  263. package/dist/src/report/render-trend.js +194 -0
  264. package/dist/src/report/render-trend.js.map +1 -0
  265. package/dist/src/report/render.d.ts +21 -0
  266. package/dist/src/report/render.d.ts.map +1 -0
  267. package/dist/src/report/render.js +286 -0
  268. package/dist/src/report/render.js.map +1 -0
  269. package/dist/src/report/run-diff.d.ts +18 -0
  270. package/dist/src/report/run-diff.d.ts.map +1 -0
  271. package/dist/src/report/run-diff.js +51 -0
  272. package/dist/src/report/run-diff.js.map +1 -0
  273. package/dist/src/report/structure.d.ts +41 -0
  274. package/dist/src/report/structure.d.ts.map +1 -0
  275. package/dist/src/report/structure.js +210 -0
  276. package/dist/src/report/structure.js.map +1 -0
  277. package/dist/src/report/trend.d.ts +26 -0
  278. package/dist/src/report/trend.d.ts.map +1 -0
  279. package/dist/src/report/trend.js +164 -0
  280. package/dist/src/report/trend.js.map +1 -0
  281. package/dist/src/report/types.d.ts +320 -0
  282. package/dist/src/report/types.d.ts.map +1 -0
  283. package/dist/src/report/types.js +11 -0
  284. package/dist/src/report/types.js.map +1 -0
  285. package/dist/src/report/util.d.ts +17 -0
  286. package/dist/src/report/util.d.ts.map +1 -0
  287. package/dist/src/report/util.js +45 -0
  288. package/dist/src/report/util.js.map +1 -0
  289. package/dist/tsconfig.tsbuildinfo +1 -1
  290. package/package.json +1 -1
  291. package/src/__tests__/adapters.test.ts +15 -8
  292. package/src/__tests__/batch-eval-parsing.test.ts +4 -2
  293. package/src/__tests__/box-model.test.ts +9 -5
  294. package/src/__tests__/browser-launch.test.ts +26 -15
  295. package/src/__tests__/cdp-client.test.ts +25 -9
  296. package/src/__tests__/close-browser.test.ts +11 -6
  297. package/src/__tests__/console-log.test.ts +36 -13
  298. package/src/__tests__/find.test.ts +58 -20
  299. package/src/__tests__/frame-command.test.ts +12 -6
  300. package/src/__tests__/open-url-navigate-error.test.ts +2 -4
  301. package/src/__tests__/output.test.ts +1 -1
  302. package/src/__tests__/profiler-heap.test.ts +191 -0
  303. package/src/__tests__/reap-idle-browser.test.ts +276 -0
  304. package/src/__tests__/ref-cache.test.ts +25 -12
  305. package/src/__tests__/report-a11y.test.ts +180 -0
  306. package/src/__tests__/report-analyze.test.ts +202 -0
  307. package/src/__tests__/report-budget.test.ts +92 -0
  308. package/src/__tests__/report-diff.test.ts +272 -0
  309. package/src/__tests__/report-evidence.test.ts +276 -0
  310. package/src/__tests__/report-flake.test.ts +214 -0
  311. package/src/__tests__/report-history.test.ts +293 -0
  312. package/src/__tests__/report-output.test.ts +210 -0
  313. package/src/__tests__/report-png.test.ts +95 -0
  314. package/src/__tests__/report-render-extras.test.ts +315 -0
  315. package/src/__tests__/report-render.test.ts +175 -0
  316. package/src/__tests__/report-run.test.ts +264 -0
  317. package/src/__tests__/session-state.test.ts +40 -28
  318. package/src/__tests__/snapshot.test.ts +60 -21
  319. package/src/__tests__/storage-eval.test.ts +30 -16
  320. package/src/__tests__/tabs.test.ts +26 -10
  321. package/src/browser/action-builder/analyzer.ts +39 -15
  322. package/src/browser/action-builder/types.ts +45 -8
  323. package/src/browser/actions.ts +288 -123
  324. package/src/browser/adapters/gemini.ts +7 -3
  325. package/src/browser/adapters/google.ts +5 -3
  326. package/src/browser/adapters/index.ts +5 -4
  327. package/src/browser/adapters/instagram.ts +4 -2
  328. package/src/browser/adapters/linkedin.ts +4 -2
  329. package/src/browser/adapters/microsoft.ts +9 -5
  330. package/src/browser/adapters/x.ts +7 -3
  331. package/src/browser/browser.ts +188 -42
  332. package/src/browser/cdp.ts +43 -11
  333. package/src/browser/console-log.ts +24 -7
  334. package/src/browser/dashboard/server.ts +44 -25
  335. package/src/browser/dashboard/ui.html +153 -165
  336. package/src/browser/dialog.ts +25 -8
  337. package/src/browser/emulation.ts +86 -36
  338. package/src/browser/find.ts +110 -47
  339. package/src/browser/har.ts +58 -26
  340. package/src/browser/index.ts +17 -16
  341. package/src/browser/network.ts +147 -46
  342. package/src/browser/pdf.ts +4 -4
  343. package/src/browser/profiler.ts +39 -19
  344. package/src/browser/record.ts +38 -19
  345. package/src/browser/ref-cache.ts +38 -17
  346. package/src/browser/screenshot.ts +58 -32
  347. package/src/browser/session.ts +51 -18
  348. package/src/browser/snapshot.ts +34 -20
  349. package/src/browser/storage.ts +73 -17
  350. package/src/browser/tabs.ts +29 -17
  351. package/src/browser/trace.ts +14 -10
  352. package/src/browser/types.ts +23 -4
  353. package/src/browser/vitals.ts +33 -16
  354. package/src/browser/wait.ts +47 -21
  355. package/src/cli/action.ts +52 -21
  356. package/src/cli/commands.ts +1365 -385
  357. package/src/cli/output.ts +5 -5
  358. package/src/cli/platform.ts +44 -23
  359. package/src/cli/types.ts +1 -1
  360. package/src/cli.ts +34 -18
  361. package/src/index.ts +2 -2
  362. package/src/report/a11y.ts +242 -0
  363. package/src/report/analyze.ts +181 -0
  364. package/src/report/budget.ts +155 -0
  365. package/src/report/collect-a11y.ts +200 -0
  366. package/src/report/collect.ts +408 -0
  367. package/src/report/evidence.ts +379 -0
  368. package/src/report/flake.ts +303 -0
  369. package/src/report/history.ts +219 -0
  370. package/src/report/index.ts +307 -0
  371. package/src/report/pixel-diff.ts +197 -0
  372. package/src/report/png.ts +290 -0
  373. package/src/report/render-evidence.ts +194 -0
  374. package/src/report/render-trend.ts +225 -0
  375. package/src/report/render.ts +314 -0
  376. package/src/report/run-diff.ts +63 -0
  377. package/src/report/structure.ts +212 -0
  378. package/src/report/trend.ts +189 -0
  379. package/src/report/types.ts +356 -0
  380. package/src/report/util.ts +48 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monobrowse",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Native browser automation via Chrome DevTools Protocol — the engine powering monomind browse",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
  * Platform adapters are pure declarations plus two tiny page-probing methods.
3
3
  * A fake PageInterface (evaluate + url) is all that's needed — no browser.
4
4
  */
5
- import { describe, it, expect, vi } from 'vitest';
5
+ import { describe, expect, it, vi } from 'vitest';
6
6
  import { adapters, getAdapter, type PageInterface } from '../browser/adapters/index.js';
7
7
 
8
8
  const PLATFORMS = ['linkedin', 'instagram', 'x', 'gemini', 'google', 'microsoft'] as const;
@@ -32,7 +32,7 @@ describe('getAdapter', () => {
32
32
 
33
33
  it('throws for an unknown platform, listing the supported ones', () => {
34
34
  expect(() => getAdapter('myspace')).toThrow(
35
- `Unknown platform: myspace. Supported: ${PLATFORMS.join(', ')}`
35
+ `Unknown platform: myspace. Supported: ${PLATFORMS.join(', ')}`,
36
36
  );
37
37
  });
38
38
 
@@ -72,12 +72,19 @@ describe('adapter invariants', () => {
72
72
 
73
73
  describe('isLoggedIn', () => {
74
74
  it('coerces the page probe to the boolean the caller expects', async () => {
75
- await expect(getAdapter('linkedin').isLoggedIn(fakePage({ evaluate: true }))).resolves.toBe(true);
76
- await expect(getAdapter('linkedin').isLoggedIn(fakePage({ evaluate: false }))).resolves.toBe(false);
75
+ await expect(getAdapter('linkedin').isLoggedIn(fakePage({ evaluate: true }))).resolves.toBe(
76
+ true,
77
+ );
78
+ await expect(getAdapter('linkedin').isLoggedIn(fakePage({ evaluate: false }))).resolves.toBe(
79
+ false,
80
+ );
77
81
  });
78
82
 
79
83
  it('google short-circuits to false on the sign-in page without probing the DOM', async () => {
80
- const page = fakePage({ url: 'https://accounts.google.com/signin/v2/identifier', evaluate: true });
84
+ const page = fakePage({
85
+ url: 'https://accounts.google.com/signin/v2/identifier',
86
+ evaluate: true,
87
+ });
81
88
  await expect(getAdapter('google').isLoggedIn(page)).resolves.toBe(false);
82
89
  expect(page.evaluated).toEqual([]);
83
90
  });
@@ -109,9 +116,9 @@ describe('isLoggedIn', () => {
109
116
  describe('extractUsername', () => {
110
117
  it('returns whatever the page evaluation yields', async () => {
111
118
  for (const key of PLATFORMS) {
112
- await expect(getAdapter(key).extractUsername(fakePage({ evaluate: 'someuser' }))).resolves.toBe(
113
- 'someuser'
114
- );
119
+ await expect(
120
+ getAdapter(key).extractUsername(fakePage({ evaluate: 'someuser' })),
121
+ ).resolves.toBe('someuser');
115
122
  }
116
123
  });
117
124
 
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from 'vitest';
1
+ import { describe, expect, it } from 'vitest';
2
2
  import { parseBatchCommandLine } from '../cli/commands.js';
3
3
 
4
4
  describe('parseBatchCommandLine — eval expressions inside a batch command string', () => {
@@ -25,7 +25,9 @@ describe('parseBatchCommandLine — eval expressions inside a batch command stri
25
25
  const input = "eval [...document.querySelectorAll('li')].map(x => x.textContent.trim())";
26
26
  const { subName, subArgs } = parseBatchCommandLine(input);
27
27
  expect(subName).toBe('eval');
28
- expect(subArgs).toEqual(["[...document.querySelectorAll('li')].map(x => x.textContent.trim())"]);
28
+ expect(subArgs).toEqual([
29
+ "[...document.querySelectorAll('li')].map(x => x.textContent.trim())",
30
+ ]);
29
31
  });
30
32
 
31
33
  it('still recognizes --json and --max-output flags placed before the expression', () => {
@@ -1,10 +1,10 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { deriveBoxOutput } from '../cli/commands.js';
1
+ import { describe, expect, it, vi } from 'vitest';
3
2
  import { getElementBox } from '../browser/snapshot.js';
4
3
  import type { ElementRef } from '../browser/types.js';
4
+ import { deriveBoxOutput } from '../cli/commands.js';
5
5
 
6
6
  describe('getElementBox (issue #15: center-vs-top-left contract)', () => {
7
- it('averages the CDP content quad\'s four corners into a center point', async () => {
7
+ it("averages the CDP content quad's four corners into a center point", async () => {
8
8
  // Content quad order per CDP DOM.getBoxModel: [x1,y1 top-left, x2,y2
9
9
  // top-right, x3,y3 bottom-right, x4,y4 bottom-left]. A 372x37 box whose
10
10
  // top-left is (454, 513.5) — matching the issue's own reproduction data.
@@ -28,8 +28,12 @@ describe('deriveBoxOutput (issue #15: get box exposing both conventions)', () =>
28
28
  const center = { x: 640, y: 532, width: 372, height: 37 };
29
29
  const result = deriveBoxOutput(center);
30
30
  expect(result).toEqual({
31
- x: 454, y: 513.5, width: 372, height: 37,
32
- centerX: 640, centerY: 532,
31
+ x: 454,
32
+ y: 513.5,
33
+ width: 372,
34
+ height: 37,
35
+ centerX: 640,
36
+ centerY: 532,
33
37
  });
34
38
  });
35
39
 
@@ -8,9 +8,10 @@
8
8
  * Fixed port range (23470-23479) chosen to avoid colliding with real
9
9
  * services; each test binds/tears down its own listeners.
10
10
  */
11
- import { describe, it, expect, afterEach } from 'vitest';
12
- import { createServer as createTcpServer, type Server as TcpServer, type Socket } from 'net';
13
- import { createServer as createHttpServer, type Server as HttpServer } from 'http';
11
+
12
+ import { createServer as createHttpServer, type Server as HttpServer } from 'node:http';
13
+ import { createServer as createTcpServer, type Socket, type Server as TcpServer } from 'node:net';
14
+ import { afterEach, describe, expect, it } from 'vitest';
14
15
  import { launchBrowser } from '../browser/browser.js';
15
16
 
16
17
  const BASE = 23470;
@@ -24,16 +25,21 @@ afterEach(async () => {
24
25
  // to close on their own, which can outlast the test. Destroy explicitly.
25
26
  for (const sock of sockets) sock.destroy();
26
27
  sockets = [];
27
- await Promise.all(servers.map(s => new Promise<void>(resolve => s.close(() => resolve()))));
28
+ await Promise.all(servers.map((s) => new Promise<void>((resolve) => s.close(() => resolve()))));
28
29
  servers = [];
29
30
  }, 5000);
30
31
 
31
32
  /** Bind a bare TCP listener — accepts connections but speaks no HTTP/CDP. */
32
33
  function occupyNonChrome(port: number): Promise<void> {
33
34
  return new Promise((resolve, reject) => {
34
- const s = createTcpServer(sock => { sockets.push(sock); /* accept and do nothing — no CDP response */ });
35
+ const s = createTcpServer((sock) => {
36
+ sockets.push(sock); /* accept and do nothing — no CDP response */
37
+ });
35
38
  s.once('error', reject);
36
- s.listen(port, '127.0.0.1', () => { servers.push(s); resolve(); });
39
+ s.listen(port, '127.0.0.1', () => {
40
+ servers.push(s);
41
+ resolve();
42
+ });
37
43
  });
38
44
  }
39
45
 
@@ -45,12 +51,16 @@ function occupyChrome(port: number): Promise<void> {
45
51
  res.writeHead(200, { 'Content-Type': 'application/json' });
46
52
  res.end(JSON.stringify({ Browser: 'Chrome/999.0.0.0' }));
47
53
  } else {
48
- res.writeHead(404); res.end();
54
+ res.writeHead(404);
55
+ res.end();
49
56
  }
50
57
  });
51
- s.on('connection', sock => sockets.push(sock));
58
+ s.on('connection', (sock) => sockets.push(sock));
52
59
  s.once('error', reject);
53
- s.listen(port, '127.0.0.1', () => { servers.push(s); resolve(); });
60
+ s.listen(port, '127.0.0.1', () => {
61
+ servers.push(s);
62
+ resolve();
63
+ });
54
64
  });
55
65
  }
56
66
 
@@ -65,8 +75,9 @@ describe('launchBrowser — port scan/attach decisions', () => {
65
75
  const port = BASE + 1;
66
76
  await occupyNonChrome(port);
67
77
  await occupyChrome(port + 1); // would succeed if scanning happened — must not be reached
68
- await expect(launchBrowser({ port, strictPort: true }))
69
- .rejects.toThrow(/does not identify as Chrome/);
78
+ await expect(launchBrowser({ port, strictPort: true })).rejects.toThrow(
79
+ /does not identify as Chrome/,
80
+ );
70
81
  });
71
82
 
72
83
  it('strictPort: attaches on an occupied Chrome requested port (identical to non-strict)', async () => {
@@ -80,7 +91,7 @@ describe('launchBrowser — port scan/attach decisions', () => {
80
91
  // Occupy the full 10-port scan window with non-Chrome listeners.
81
92
  for (let i = 0; i < 10; i++) await occupyNonChrome(port + i);
82
93
  await expect(launchBrowser({ port })).rejects.toThrow(
83
- new RegExp(`Ports ${port}-${port + 9} are all occupied`)
94
+ new RegExp(`Ports ${port}-${port + 9} are all occupied`),
84
95
  );
85
96
  }, 15000); // generous margin — 10 candidates, each a fast isTcpPortOpen check
86
97
 
@@ -92,11 +103,11 @@ describe('launchBrowser — port scan/attach decisions', () => {
92
103
  // skipped, so if every candidate is occupied the call still fails even
93
104
  // though one of them is an attachable Chrome.
94
105
  const port = BASE + 4;
95
- await occupyNonChrome(port); // requested port: occupied, not Chrome
96
- await occupyChrome(port + 1); // scanned candidate: IS Chrome — must be skipped, not attached
106
+ await occupyNonChrome(port); // requested port: occupied, not Chrome
107
+ await occupyChrome(port + 1); // scanned candidate: IS Chrome — must be skipped, not attached
97
108
  for (let i = 2; i < 10; i++) await occupyNonChrome(port + i); // remaining candidates: occupied
98
109
  await expect(launchBrowser({ port })).rejects.toThrow(
99
- new RegExp(`Ports ${port}-${port + 9} are all occupied`)
110
+ new RegExp(`Ports ${port}-${port + 9} are all occupied`),
100
111
  );
101
112
  }, 15000); // generous margin — 10 candidates, each a fast isTcpPortOpen check
102
113
  });
@@ -5,7 +5,7 @@
5
5
  * `ws` module (so we can drive 'message'/'close'/'error' by hand), and
6
6
  * fetchTargets/fetchNewTarget run against a stubbed global fetch.
7
7
  */
8
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
8
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
9
9
 
10
10
  // --- fake `ws` -------------------------------------------------------------
11
11
  // Captures the most recently constructed socket so tests can drive its events.
@@ -140,7 +140,9 @@ describe('send', () => {
140
140
  it('refuses to exceed the 1000 in-flight command cap', async () => {
141
141
  const { client } = await connected();
142
142
  const inflight = Array.from({ length: 1000 }, () => client.send('A').catch(() => {}));
143
- await expect(client.send('A')).rejects.toThrow('CDP command queue full (>1000 in-flight commands)');
143
+ await expect(client.send('A')).rejects.toThrow(
144
+ 'CDP command queue full (>1000 in-flight commands)',
145
+ );
144
146
  client.close();
145
147
  await Promise.all(inflight);
146
148
  });
@@ -152,7 +154,9 @@ describe('send', () => {
152
154
  it('rejects a command with no response after the default 30s timeout', async () => {
153
155
  const { client } = await connected();
154
156
  const p = client.send('Runtime.evaluate');
155
- const assertion = expect(p).rejects.toThrow('CDP command "Runtime.evaluate" timed out after 30000ms');
157
+ const assertion = expect(p).rejects.toThrow(
158
+ 'CDP command "Runtime.evaluate" timed out after 30000ms',
159
+ );
156
160
  await vi.advanceTimersByTimeAsync(30_000);
157
161
  await assertion;
158
162
  });
@@ -171,7 +175,13 @@ describe('send', () => {
171
175
  await vi.advanceTimersByTimeAsync(60_000);
172
176
  // Still pending — no timeout fired.
173
177
  let settled = false;
174
- void p.then(() => { settled = true; }).catch(() => { settled = true; });
178
+ void p
179
+ .then(() => {
180
+ settled = true;
181
+ })
182
+ .catch(() => {
183
+ settled = true;
184
+ });
175
185
  await Promise.resolve();
176
186
  expect(settled).toBe(false);
177
187
  ws.deliver({ id: 1, result: {} });
@@ -331,21 +341,27 @@ describe('fetchTargets / fetchNewTarget', () => {
331
341
  globalThis.fetch = realFetch;
332
342
  });
333
343
 
334
- function stubFetch(impl: (url: string, init?: RequestInit) => Response): ReturnType<typeof vi.fn> {
344
+ function stubFetch(
345
+ impl: (url: string, init?: RequestInit) => Response,
346
+ ): ReturnType<typeof vi.fn> {
335
347
  const fn = vi.fn((url: string, init?: RequestInit) => Promise.resolve(impl(url, init)));
336
348
  globalThis.fetch = fn as unknown as typeof fetch;
337
349
  return fn;
338
350
  }
339
351
 
340
352
  it('fetchTargets hits /json/list on the given port', async () => {
341
- const fn = stubFetch(() => new Response(JSON.stringify([{ id: 'T1', type: 'page' }]), { status: 200 }));
353
+ const fn = stubFetch(
354
+ () => new Response(JSON.stringify([{ id: 'T1', type: 'page' }]), { status: 200 }),
355
+ );
342
356
  await expect(fetchTargets(9333)).resolves.toEqual([{ id: 'T1', type: 'page' }]);
343
357
  expect(fn.mock.calls[0]![0]).toBe('http://127.0.0.1:9333/json/list');
344
358
  });
345
359
 
346
360
  it('fetchTargets throws on a non-OK response', async () => {
347
361
  stubFetch(() => new Response('nope', { status: 500, statusText: 'Internal Server Error' }));
348
- await expect(fetchTargets(9222)).rejects.toThrow('Failed to fetch targets: Internal Server Error');
362
+ await expect(fetchTargets(9222)).rejects.toThrow(
363
+ 'Failed to fetch targets: Internal Server Error',
364
+ );
349
365
  });
350
366
 
351
367
  it('fetchNewTarget uses PUT and percent-encodes the URL', async () => {
@@ -354,7 +370,7 @@ describe('fetchTargets / fetchNewTarget', () => {
354
370
  const [url, init] = fn.mock.calls[0] as [string, RequestInit];
355
371
  expect(init.method).toBe('PUT');
356
372
  expect(url).toBe(
357
- 'http://127.0.0.1:9222/json/new?' + encodeURIComponent('https://x.test/a?b=1&c=2')
373
+ `http://127.0.0.1:9222/json/new?${encodeURIComponent('https://x.test/a?b=1&c=2')}`,
358
374
  );
359
375
  // The query separators of the target URL must not leak into Chrome's own query.
360
376
  expect(url.split('?').length).toBe(2);
@@ -363,7 +379,7 @@ describe('fetchTargets / fetchNewTarget', () => {
363
379
  it('fetchNewTarget throws on a non-OK response', async () => {
364
380
  stubFetch(() => new Response('', { status: 405, statusText: 'Method Not Allowed' }));
365
381
  await expect(fetchNewTarget(9222, 'about:blank')).rejects.toThrow(
366
- 'Failed to create target: Method Not Allowed'
382
+ 'Failed to create target: Method Not Allowed',
367
383
  );
368
384
  });
369
385
 
@@ -11,11 +11,12 @@
11
11
  * fake `ws` socket (same pattern as cdp-client.test.ts), and process.kill is
12
12
  * spied on rather than actually signaling anything.
13
13
  */
14
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
15
- import { mkdtemp, rm, mkdir, writeFile } from 'fs/promises';
16
- import { setTimeout as realDelay } from 'timers/promises';
17
- import { join } from 'path';
18
- import { tmpdir } from 'os';
14
+
15
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
16
+ import { tmpdir } from 'node:os';
17
+ import { join } from 'node:path';
18
+ import { setTimeout as realDelay } from 'node:timers/promises';
19
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
19
20
 
20
21
  let lastSocket: FakeWs | null = null;
21
22
 
@@ -73,7 +74,11 @@ afterEach(async () => {
73
74
  async function writePersistedPort(port: number, pid: number, savedAt: number): Promise<void> {
74
75
  const dir = join(tempDir, '.monomind', 'monobrowse');
75
76
  await mkdir(dir, { recursive: true });
76
- await writeFile(join(dir, 'active-port.json'), JSON.stringify({ port, pid, launched: true, savedAt }), 'utf-8');
77
+ await writeFile(
78
+ join(dir, 'active-port.json'),
79
+ JSON.stringify({ port, pid, launched: true, savedAt }),
80
+ 'utf-8',
81
+ );
77
82
  }
78
83
 
79
84
  /**
@@ -3,14 +3,14 @@
3
3
  * two per-session Maps. Nothing here touches a browser — we hand it a fake
4
4
  * client that just records handlers and lets us fire events by hand.
5
5
  */
6
- import { describe, it, expect, beforeEach } from 'vitest';
6
+ import { beforeEach, describe, expect, it } from 'vitest';
7
7
  import type { CdpClient } from '../browser/cdp.js';
8
8
  import {
9
- setupConsoleCapture,
10
- getConsoleMessages,
11
9
  clearConsoleMessages,
12
- getPageErrors,
13
10
  clearPageErrors,
11
+ getConsoleMessages,
12
+ getPageErrors,
13
+ setupConsoleCapture,
14
14
  teardownConsoleCapture,
15
15
  } from '../browser/console-log.js';
16
16
 
@@ -91,13 +91,17 @@ describe('Runtime.consoleAPICalled capture', () => {
91
91
  client.emit(
92
92
  'Runtime.consoleAPICalled',
93
93
  { type: 'log', args: [{ value: 'count:' }, { value: 42 }, { description: 'Object {a: 1}' }] },
94
- 'S1'
94
+ 'S1',
95
95
  );
96
96
  expect(getConsoleMessages('S1')[0]!.text).toBe('count: 42 Object {a: 1}');
97
97
  });
98
98
 
99
99
  it('normalizes CDP\'s "warning" to the "warn" type used by ConsoleMessage', () => {
100
- client.emit('Runtime.consoleAPICalled', { type: 'warning', args: [{ value: 'careful' }] }, 'S1');
100
+ client.emit(
101
+ 'Runtime.consoleAPICalled',
102
+ { type: 'warning', args: [{ value: 'careful' }] },
103
+ 'S1',
104
+ );
101
105
  expect(getConsoleMessages('S1')[0]!.type).toBe('warn');
102
106
  });
103
107
 
@@ -123,8 +127,15 @@ describe('Log.entryAdded capture', () => {
123
127
  it('records text, url and lineNumber and maps "warning" to "warn"', () => {
124
128
  client.emit(
125
129
  'Log.entryAdded',
126
- { entry: { level: 'warning', text: 'deprecated API', url: 'https://x.test/a.js', lineNumber: 17 } },
127
- 'S1'
130
+ {
131
+ entry: {
132
+ level: 'warning',
133
+ text: 'deprecated API',
134
+ url: 'https://x.test/a.js',
135
+ lineNumber: 17,
136
+ },
137
+ },
138
+ 'S1',
128
139
  );
129
140
  const [msg] = getConsoleMessages('S1');
130
141
  expect(msg).toMatchObject({
@@ -156,7 +167,7 @@ describe('Runtime.exceptionThrown capture', () => {
156
167
  columnNumber: 9,
157
168
  },
158
169
  },
159
- 'S1'
170
+ 'S1',
160
171
  );
161
172
  expect(getPageErrors('S1')[0]).toMatchObject({
162
173
  text: 'TypeError: x is not a function',
@@ -167,7 +178,11 @@ describe('Runtime.exceptionThrown capture', () => {
167
178
  });
168
179
 
169
180
  it('falls back to text, then to "Unknown error"', () => {
170
- client.emit('Runtime.exceptionThrown', { exceptionDetails: { text: 'Uncaught (in promise)' } }, 'S1');
181
+ client.emit(
182
+ 'Runtime.exceptionThrown',
183
+ { exceptionDetails: { text: 'Uncaught (in promise)' } },
184
+ 'S1',
185
+ );
171
186
  client.emit('Runtime.exceptionThrown', { exceptionDetails: {} }, 'S1');
172
187
  expect(getPageErrors('S1').map((e) => e.text)).toEqual([
173
188
  'Uncaught (in promise)',
@@ -191,14 +206,22 @@ describe('multi-session isolation and clearing', () => {
191
206
  client.emit('Runtime.exceptionThrown', { exceptionDetails: { text: 'e2' } }, 'S2');
192
207
  });
193
208
 
194
- it('keeps each session\'s buffers separate', () => {
209
+ it("keeps each session's buffers separate", () => {
195
210
  expect(getConsoleMessages('S1').map((m) => m.text)).toEqual(['one']);
196
211
  expect(getConsoleMessages('S2').map((m) => m.text)).toEqual(['two']);
197
212
  });
198
213
 
199
214
  it('returns a flattened view across sessions when no session id is given', () => {
200
- expect(getConsoleMessages().map((m) => m.text).sort()).toEqual(['one', 'two']);
201
- expect(getPageErrors().map((e) => e.text).sort()).toEqual(['e1', 'e2']);
215
+ expect(
216
+ getConsoleMessages()
217
+ .map((m) => m.text)
218
+ .sort(),
219
+ ).toEqual(['one', 'two']);
220
+ expect(
221
+ getPageErrors()
222
+ .map((e) => e.text)
223
+ .sort(),
224
+ ).toEqual(['e1', 'e2']);
202
225
  });
203
226
 
204
227
  it('returns a copy, so mutating the result does not corrupt the buffer', () => {
@@ -5,21 +5,21 @@
5
5
  * browser at all: they filter the in-memory ref Map. findBySelector and
6
6
  * findByTestId do issue CDP commands, which a recording stub answers.
7
7
  */
8
- import { describe, it, expect, vi } from 'vitest';
8
+ import { describe, expect, it, vi } from 'vitest';
9
9
  import type { CdpClient } from '../browser/cdp.js';
10
- import type { ElementRef } from '../browser/types.js';
11
10
  import {
12
- findBySelector,
13
- findByRole,
14
- findByText,
15
11
  findByLabel,
16
12
  findByPlaceholder,
13
+ findByRole,
14
+ findBySelector,
17
15
  findByTestId,
16
+ findByText,
17
+ isChecked,
18
18
  isEnabled,
19
19
  isVisible,
20
- isChecked,
21
20
  scrollIntoView,
22
21
  } from '../browser/find.js';
22
+ import type { ElementRef } from '../browser/types.js';
23
23
 
24
24
  function ref(partial: Partial<ElementRef> & { ref: string }): ElementRef {
25
25
  return { role: 'generic', name: '', nodeId: 1, ...partial };
@@ -31,8 +31,21 @@ function sampleRefs(): Map<string, ElementRef> {
31
31
  ref({ ref: 'e1', role: 'button', name: 'Save changes', backendDOMNodeId: 11 }),
32
32
  ref({ ref: 'e2', role: 'BUTTON', name: 'Save', backendDOMNodeId: 12 }),
33
33
  ref({ ref: 'e3', role: 'link', name: 'Save as draft', backendDOMNodeId: 13 }),
34
- ref({ ref: 'e4', role: 'textbox', name: 'Email', placeholder: 'you@example.com', backendDOMNodeId: 14 }),
35
- ref({ ref: 'e5', role: 'textbox', name: 'Notes', placeholder: 'Optional notes', backendDOMNodeId: 15, disabled: true }),
34
+ ref({
35
+ ref: 'e4',
36
+ role: 'textbox',
37
+ name: 'Email',
38
+ placeholder: 'you@example.com',
39
+ backendDOMNodeId: 14,
40
+ }),
41
+ ref({
42
+ ref: 'e5',
43
+ role: 'textbox',
44
+ name: 'Notes',
45
+ placeholder: 'Optional notes',
46
+ backendDOMNodeId: 15,
47
+ disabled: true,
48
+ }),
36
49
  ];
37
50
  return new Map(entries.map((e) => [e.ref, e]));
38
51
  }
@@ -84,8 +97,12 @@ describe('findByRole', () => {
84
97
 
85
98
  it('requires a full name match under exact', async () => {
86
99
  const { client } = stubClient();
87
- expect((await findByRole(client, 'S1', sampleRefs(), 'button', { name: 'Save', exact: true }))?.ref).toBe('e2');
88
- expect(await findByRole(client, 'S1', sampleRefs(), 'button', { name: 'Sav', exact: true })).toBeNull();
100
+ expect(
101
+ (await findByRole(client, 'S1', sampleRefs(), 'button', { name: 'Save', exact: true }))?.ref,
102
+ ).toBe('e2');
103
+ expect(
104
+ await findByRole(client, 'S1', sampleRefs(), 'button', { name: 'Sav', exact: true }),
105
+ ).toBeNull();
89
106
  });
90
107
 
91
108
  it('nth is 1-based over the filtered matches', async () => {
@@ -98,7 +115,9 @@ describe('findByRole', () => {
98
115
 
99
116
  it('last returns the final match', async () => {
100
117
  const { client } = stubClient();
101
- expect((await findByRole(client, 'S1', sampleRefs(), 'button', { last: true }))?.ref).toBe('e2');
118
+ expect((await findByRole(client, 'S1', sampleRefs(), 'button', { last: true }))?.ref).toBe(
119
+ 'e2',
120
+ );
102
121
  });
103
122
 
104
123
  it('returns null when no ref carries that role', async () => {
@@ -141,7 +160,9 @@ describe('findByText', () => {
141
160
  it('findByLabel delegates to the same matching', async () => {
142
161
  const { client } = stubClient();
143
162
  const refs = sampleRefs();
144
- expect(await findByLabel(client, 'S1', refs, 'Email')).toBe(await findByText(client, 'S1', refs, 'Email'));
163
+ expect(await findByLabel(client, 'S1', refs, 'Email')).toBe(
164
+ await findByText(client, 'S1', refs, 'Email'),
165
+ );
145
166
  });
146
167
  });
147
168
 
@@ -154,14 +175,18 @@ describe('findByPlaceholder', () => {
154
175
  it('treats a missing placeholder as empty rather than crashing', async () => {
155
176
  const { client } = stubClient();
156
177
  // e1..e3 have no placeholder; an empty needle must not match them under exact.
157
- expect((await findByPlaceholder(client, 'S1', sampleRefs(), '', { exact: true }))?.ref).toBe('e1');
178
+ expect((await findByPlaceholder(client, 'S1', sampleRefs(), '', { exact: true }))?.ref).toBe(
179
+ 'e1',
180
+ );
158
181
  expect(await findByPlaceholder(client, 'S1', sampleRefs(), 'nope')).toBeNull();
159
182
  });
160
183
 
161
184
  it('honours exact, nth and last', async () => {
162
185
  const { client } = stubClient();
163
186
  const refs = sampleRefs();
164
- expect((await findByPlaceholder(client, 'S1', refs, 'Optional notes', { exact: true }))?.ref).toBe('e5');
187
+ expect(
188
+ (await findByPlaceholder(client, 'S1', refs, 'Optional notes', { exact: true }))?.ref,
189
+ ).toBe('e5');
165
190
  expect((await findByPlaceholder(client, 'S1', refs, 'o', { nth: 1 }))?.ref).toBe('e4');
166
191
  expect((await findByPlaceholder(client, 'S1', refs, 'o', { last: true }))?.ref).toBe('e5');
167
192
  });
@@ -190,7 +215,12 @@ describe('findBySelector', () => {
190
215
  });
191
216
  const refs = sampleRefs();
192
217
  const found = await findBySelector(client, 'S1', refs, 'div.hidden');
193
- expect(found).toMatchObject({ ref: 'sel-999', role: 'generic', name: 'div.hidden', nodeId: 55 });
218
+ expect(found).toMatchObject({
219
+ ref: 'sel-999',
220
+ role: 'generic',
221
+ name: 'div.hidden',
222
+ nodeId: 55,
223
+ });
194
224
  expect(refs.get('sel-999')).toBe(found);
195
225
  });
196
226
 
@@ -242,7 +272,9 @@ describe('findBySelector', () => {
242
272
  'DOM.getDocument': doc,
243
273
  'DOM.querySelector': new Error("SyntaxError: '((' is not a valid selector"),
244
274
  });
245
- await expect(findBySelector(client, 'S1', sampleRefs(), '((')).rejects.toThrow(/not a valid selector/);
275
+ await expect(findBySelector(client, 'S1', sampleRefs(), '((')).rejects.toThrow(
276
+ /not a valid selector/,
277
+ );
246
278
  });
247
279
 
248
280
  it('swallows transient CDP errors and reports not-found', async () => {
@@ -282,7 +314,9 @@ describe('findByTestId', () => {
282
314
  });
283
315
 
284
316
  it('returns null when no attribute form matches', async () => {
285
- const client = { send: vi.fn(async () => ({ result: { value: false } })) } as unknown as CdpClient;
317
+ const client = {
318
+ send: vi.fn(async () => ({ result: { value: false } })),
319
+ } as unknown as CdpClient;
286
320
  await expect(findByTestId(client, 'S1', 'nope')).resolves.toBeNull();
287
321
  });
288
322
 
@@ -330,7 +364,9 @@ describe('element state helpers', () => {
330
364
  'DOM.resolveNode': { object: { objectId: 'OBJ1' } },
331
365
  'Runtime.callFunctionOn': { result: { value: true } },
332
366
  });
333
- await expect(isVisible(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 }))).resolves.toBe(true);
367
+ await expect(isVisible(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 }))).resolves.toBe(
368
+ true,
369
+ );
334
370
  expect(calls.find((c) => c.method === 'Runtime.callFunctionOn')!.params).toMatchObject({
335
371
  objectId: 'OBJ1',
336
372
  returnByValue: true,
@@ -342,13 +378,15 @@ describe('element state helpers', () => {
342
378
  'DOM.resolveNode': { object: { objectId: 'OBJ1' } },
343
379
  'Runtime.callFunctionOn': { result: {} },
344
380
  });
345
- await expect(isChecked(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 }))).resolves.toBe(false);
381
+ await expect(isChecked(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 }))).resolves.toBe(
382
+ false,
383
+ );
346
384
  });
347
385
 
348
386
  it('scrollIntoView throws a ref-named error when the node is gone', async () => {
349
387
  const { client } = stubClient({ 'DOM.resolveNode': { object: {} } });
350
388
  await expect(
351
- scrollIntoView(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 }))
389
+ scrollIntoView(client, 'S1', ref({ ref: 'e1', backendDOMNodeId: 11 })),
352
390
  ).rejects.toThrow('Cannot scroll: ref @e1 not found in DOM');
353
391
  });
354
392
  });
@@ -4,7 +4,7 @@
4
4
  * frame, and `frame main` must detach the frame session and restore the
5
5
  * page session. The browser engine is mocked; no real Chrome.
6
6
  */
7
- import { describe, it, expect, beforeEach, vi } from 'vitest';
7
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
8
8
  import type { Command, CommandContext } from '../cli/types.js';
9
9
 
10
10
  const mocks = vi.hoisted(() => {
@@ -22,7 +22,12 @@ const mocks = vi.hoisted(() => {
22
22
  })),
23
23
  loadActivePortInfo: vi.fn(async () => null),
24
24
  loadRefCache: vi.fn(async () => null),
25
- switchToFrame: vi.fn(async (): Promise<{ url: string | null; sessionId: string | null }> => ({ url: 'https://f.test/frame', sessionId: 'S-FRAME' })),
25
+ switchToFrame: vi.fn(
26
+ async (): Promise<{ url: string | null; sessionId: string | null }> => ({
27
+ url: 'https://f.test/frame',
28
+ sessionId: 'S-FRAME',
29
+ }),
30
+ ),
26
31
  enableSessionDomains: vi.fn(async () => {}),
27
32
  teardownRouteInterception: vi.fn(),
28
33
  stopRequestCapture: vi.fn(),
@@ -52,7 +57,10 @@ beforeEach(() => {
52
57
  vi.clearAllMocks();
53
58
  mocks.browser.loadActivePortInfo.mockResolvedValue(null);
54
59
  mocks.browser.loadRefCache.mockResolvedValue(null);
55
- mocks.browser.switchToFrame.mockResolvedValue({ url: 'https://f.test/frame', sessionId: 'S-FRAME' });
60
+ mocks.browser.switchToFrame.mockResolvedValue({
61
+ url: 'https://f.test/frame',
62
+ sessionId: 'S-FRAME',
63
+ });
56
64
  mocks.browser.connectToTarget.mockResolvedValue({
57
65
  client: mocks.client,
58
66
  sessionId: 'S-PAGE',
@@ -72,9 +80,7 @@ describe('browse frame command (#97)', () => {
72
80
 
73
81
  // Back to main — must detach the FRAME session (proves _sessionId was updated)
74
82
  await frame.action!(ctx(['main']));
75
- const detach = mocks.send.mock.calls.find(
76
- ([m]) => m === 'Target.detachFromTarget'
77
- );
83
+ const detach = mocks.send.mock.calls.find(([m]) => m === 'Target.detachFromTarget');
78
84
  expect(detach).toBeDefined();
79
85
  expect(detach![1]).toEqual({ sessionId: 'S-FRAME' });
80
86