@rehearsal-labs/retest 0.1.0 → 0.3.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 (502) hide show
  1. package/README.md +12 -5
  2. package/dist/agent/session.d.ts +21 -2
  3. package/dist/agent/session.d.ts.map +1 -1
  4. package/dist/agent/session.js +73 -11
  5. package/dist/api/app-page.d.ts +39 -3
  6. package/dist/api/app-page.d.ts.map +1 -1
  7. package/dist/api/app-page.js +108 -0
  8. package/dist/api/dialog.d.ts +38 -0
  9. package/dist/api/dialog.d.ts.map +1 -0
  10. package/dist/api/dialog.js +78 -0
  11. package/dist/api/drag.d.ts +32 -0
  12. package/dist/api/drag.d.ts.map +1 -0
  13. package/dist/api/drag.js +26 -0
  14. package/dist/api/files.d.ts +49 -0
  15. package/dist/api/files.d.ts.map +1 -0
  16. package/dist/api/files.js +168 -0
  17. package/dist/api/inbox.d.ts +97 -0
  18. package/dist/api/inbox.d.ts.map +1 -0
  19. package/dist/api/inbox.js +191 -0
  20. package/dist/api/locator-recipes.d.ts +1 -1
  21. package/dist/api/locator-recipes.d.ts.map +1 -1
  22. package/dist/api/locator-recipes.js +4 -3
  23. package/dist/api/page.d.ts +214 -4
  24. package/dist/api/page.d.ts.map +1 -1
  25. package/dist/api/route.d.ts +21 -0
  26. package/dist/api/route.d.ts.map +1 -0
  27. package/dist/api/route.js +99 -0
  28. package/dist/api/source-location.d.ts.map +1 -1
  29. package/dist/api/source-location.js +3 -1
  30. package/dist/api/test-run.d.ts +127 -1
  31. package/dist/api/test-run.d.ts.map +1 -1
  32. package/dist/api/test-run.js +293 -0
  33. package/dist/assertions/expect.d.ts +91 -2
  34. package/dist/assertions/expect.d.ts.map +1 -1
  35. package/dist/assertions/expect.js +98 -0
  36. package/dist/assertions/look-until.d.ts +5 -0
  37. package/dist/assertions/look-until.d.ts.map +1 -1
  38. package/dist/assertions/look-until.js +1 -1
  39. package/dist/assertions/poll-layout.d.ts +24 -0
  40. package/dist/assertions/poll-layout.d.ts.map +1 -0
  41. package/dist/assertions/poll-layout.js +63 -0
  42. package/dist/assertions/screenshot.d.ts +36 -0
  43. package/dist/assertions/screenshot.d.ts.map +1 -0
  44. package/dist/assertions/screenshot.js +125 -0
  45. package/dist/browser/accessibility.d.ts.map +1 -1
  46. package/dist/browser/accessibility.js +22 -1
  47. package/dist/browser/actionability.d.ts +9 -6
  48. package/dist/browser/actionability.d.ts.map +1 -1
  49. package/dist/browser/actionability.js +17 -8
  50. package/dist/browser/browser.d.ts.map +1 -1
  51. package/dist/browser/browser.js +15 -4
  52. package/dist/browser/builds.d.ts +35 -6
  53. package/dist/browser/builds.d.ts.map +1 -1
  54. package/dist/browser/builds.js +115 -16
  55. package/dist/browser/cdp/connection.d.ts +6 -0
  56. package/dist/browser/cdp/connection.d.ts.map +1 -1
  57. package/dist/browser/cdp/connection.js +8 -0
  58. package/dist/browser/cdp/transport.d.ts.map +1 -1
  59. package/dist/browser/cdp/transport.js +4 -4
  60. package/dist/browser/checked-state.d.ts +2 -2
  61. package/dist/browser/checked-state.d.ts.map +1 -1
  62. package/dist/browser/chromium-process.d.ts +32 -2
  63. package/dist/browser/chromium-process.d.ts.map +1 -1
  64. package/dist/browser/chromium-process.js +95 -17
  65. package/dist/browser/contract.d.ts +119 -5
  66. package/dist/browser/contract.d.ts.map +1 -1
  67. package/dist/browser/dialogs.d.ts +157 -0
  68. package/dist/browser/dialogs.d.ts.map +1 -0
  69. package/dist/browser/dialogs.js +271 -0
  70. package/dist/browser/downloads.d.ts +71 -0
  71. package/dist/browser/downloads.d.ts.map +1 -0
  72. package/dist/browser/downloads.js +253 -0
  73. package/dist/browser/drag.d.ts +50 -0
  74. package/dist/browser/drag.d.ts.map +1 -0
  75. package/dist/browser/drag.js +584 -0
  76. package/dist/browser/electron-window-watch.d.ts +32 -0
  77. package/dist/browser/electron-window-watch.d.ts.map +1 -0
  78. package/dist/browser/electron-window-watch.js +93 -0
  79. package/dist/browser/electron.d.ts +14 -3
  80. package/dist/browser/electron.d.ts.map +1 -1
  81. package/dist/browser/electron.js +57 -9
  82. package/dist/browser/element-queries.d.ts +51 -15
  83. package/dist/browser/element-queries.d.ts.map +1 -1
  84. package/dist/browser/element-queries.js +92 -13
  85. package/dist/browser/emulation.d.ts.map +1 -1
  86. package/dist/browser/emulation.js +7 -5
  87. package/dist/browser/executables.d.ts +16 -1
  88. package/dist/browser/executables.d.ts.map +1 -1
  89. package/dist/browser/executables.js +50 -18
  90. package/dist/browser/file-chooser.d.ts +75 -0
  91. package/dist/browser/file-chooser.d.ts.map +1 -0
  92. package/dist/browser/file-chooser.js +449 -0
  93. package/dist/browser/firefox/accessible-names.d.ts +5 -4
  94. package/dist/browser/firefox/accessible-names.d.ts.map +1 -1
  95. package/dist/browser/firefox/accessible-names.js +11 -6
  96. package/dist/browser/firefox/bridge.js +3 -2
  97. package/dist/browser/firefox/executable.d.ts +14 -14
  98. package/dist/browser/firefox/executable.d.ts.map +1 -1
  99. package/dist/browser/firefox/executable.js +29 -21
  100. package/dist/browser/firefox/input.d.ts +5 -0
  101. package/dist/browser/firefox/input.d.ts.map +1 -1
  102. package/dist/browser/firefox/input.js +6 -3
  103. package/dist/browser/firefox/launch.js +1 -1
  104. package/dist/browser/firefox/navigation.d.ts +5 -2
  105. package/dist/browser/firefox/navigation.d.ts.map +1 -1
  106. package/dist/browser/firefox/navigation.js +48 -14
  107. package/dist/browser/firefox/orphans.d.ts.map +1 -1
  108. package/dist/browser/firefox/orphans.js +34 -2
  109. package/dist/browser/firefox/page.d.ts +11 -1
  110. package/dist/browser/firefox/page.d.ts.map +1 -1
  111. package/dist/browser/firefox/page.js +179 -26
  112. package/dist/browser/firefox/process.d.ts +20 -1
  113. package/dist/browser/firefox/process.d.ts.map +1 -1
  114. package/dist/browser/firefox/process.js +124 -22
  115. package/dist/browser/firefox/profile.d.ts +5 -0
  116. package/dist/browser/firefox/profile.d.ts.map +1 -1
  117. package/dist/browser/firefox/profile.js +17 -1
  118. package/dist/browser/firefox/storage.d.ts.map +1 -1
  119. package/dist/browser/firefox/storage.js +4 -2
  120. package/dist/browser/firefox/subscriptions.d.ts +26 -0
  121. package/dist/browser/firefox/subscriptions.d.ts.map +1 -0
  122. package/dist/browser/firefox/subscriptions.js +10 -0
  123. package/dist/browser/frames.d.ts +205 -0
  124. package/dist/browser/frames.d.ts.map +1 -0
  125. package/dist/browser/frames.js +657 -0
  126. package/dist/browser/input-guard.d.ts +18 -5
  127. package/dist/browser/input-guard.d.ts.map +1 -1
  128. package/dist/browser/input-guard.js +65 -6
  129. package/dist/browser/isolated-world.d.ts +8 -1
  130. package/dist/browser/isolated-world.d.ts.map +1 -1
  131. package/dist/browser/launch.d.ts +6 -0
  132. package/dist/browser/launch.d.ts.map +1 -1
  133. package/dist/browser/launch.js +14 -1
  134. package/dist/browser/layout.d.ts +120 -0
  135. package/dist/browser/layout.d.ts.map +1 -0
  136. package/dist/browser/layout.js +213 -0
  137. package/dist/browser/locate.d.ts +10 -0
  138. package/dist/browser/locate.d.ts.map +1 -1
  139. package/dist/browser/locate.js +24 -6
  140. package/dist/browser/origin-document.d.ts +4 -0
  141. package/dist/browser/origin-document.d.ts.map +1 -1
  142. package/dist/browser/origin-document.js +9 -1
  143. package/dist/browser/page-scripts.d.ts +48 -0
  144. package/dist/browser/page-scripts.d.ts.map +1 -1
  145. package/dist/browser/page-scripts.js +515 -39
  146. package/dist/browser/page.d.ts +60 -1
  147. package/dist/browser/page.d.ts.map +1 -1
  148. package/dist/browser/page.js +275 -32
  149. package/dist/browser/popups.d.ts +166 -0
  150. package/dist/browser/popups.d.ts.map +1 -0
  151. package/dist/browser/popups.js +317 -0
  152. package/dist/browser/routes.d.ts +97 -0
  153. package/dist/browser/routes.d.ts.map +1 -0
  154. package/dist/browser/routes.js +226 -0
  155. package/dist/browser/screenshot.d.ts +44 -0
  156. package/dist/browser/screenshot.d.ts.map +1 -0
  157. package/dist/browser/screenshot.js +51 -0
  158. package/dist/browser/shadow-candidates.d.ts +20 -0
  159. package/dist/browser/shadow-candidates.d.ts.map +1 -0
  160. package/dist/browser/shadow-candidates.js +77 -0
  161. package/dist/browser/webkit/page.d.ts +11 -1
  162. package/dist/browser/webkit/page.d.ts.map +1 -1
  163. package/dist/browser/webkit/page.js +53 -2
  164. package/dist/browser/webkit/relay.d.ts.map +1 -1
  165. package/dist/browser/webkit/relay.js +5 -1
  166. package/dist/cli/commands/doctor.js +3 -3
  167. package/dist/cli/commands/inspect.js +3 -2
  168. package/dist/cli/commands/install.d.ts.map +1 -1
  169. package/dist/cli/commands/install.js +26 -13
  170. package/dist/cli/commands/licences.d.ts +22 -0
  171. package/dist/cli/commands/licences.d.ts.map +1 -1
  172. package/dist/cli/commands/licences.js +62 -20
  173. package/dist/cli/commands/run.d.ts.map +1 -1
  174. package/dist/cli/commands/run.js +4 -2
  175. package/dist/cli/doctor/checks.js +4 -1
  176. package/dist/cli/inspect/diagnostics.js +3 -3
  177. package/dist/cli/inspect/test-timeline.d.ts.map +1 -1
  178. package/dist/cli/inspect/test-timeline.js +45 -11
  179. package/dist/cli/install/doctor-rows.d.ts.map +1 -1
  180. package/dist/cli/install/doctor-rows.js +5 -4
  181. package/dist/cli/install/file-changes.d.ts +44 -0
  182. package/dist/cli/install/file-changes.d.ts.map +1 -0
  183. package/dist/cli/install/file-changes.js +81 -0
  184. package/dist/cli/install/install-archive.d.ts +3 -1
  185. package/dist/cli/install/install-archive.d.ts.map +1 -1
  186. package/dist/cli/install/install-archive.js +80 -33
  187. package/dist/cli/install/lock.d.ts.map +1 -1
  188. package/dist/cli/install/lock.js +108 -21
  189. package/dist/cli/install/media-doctor.d.ts.map +1 -1
  190. package/dist/cli/install/media-doctor.js +2 -1
  191. package/dist/cli/install/media-install.d.ts.map +1 -1
  192. package/dist/cli/install/media-install.js +38 -19
  193. package/dist/cli/install/media-pins.d.ts +7 -1
  194. package/dist/cli/install/media-pins.d.ts.map +1 -1
  195. package/dist/cli/install/media-pins.js +23 -12
  196. package/dist/cli/install/media-record.d.ts.map +1 -1
  197. package/dist/cli/install/media-record.js +10 -9
  198. package/dist/cli/install/media-report.d.ts +3 -1
  199. package/dist/cli/install/media-report.d.ts.map +1 -1
  200. package/dist/cli/install/media-report.js +7 -5
  201. package/dist/cli/install/media-tools.d.ts.map +1 -1
  202. package/dist/cli/install/media-tools.js +6 -4
  203. package/dist/cli/install/process-start.d.ts +3 -2
  204. package/dist/cli/install/process-start.d.ts.map +1 -1
  205. package/dist/cli/install/process-start.js +4 -0
  206. package/dist/cli/install/report.d.ts.map +1 -1
  207. package/dist/cli/install/report.js +11 -7
  208. package/dist/cli/install/supervisor-install.d.ts +33 -0
  209. package/dist/cli/install/supervisor-install.d.ts.map +1 -0
  210. package/dist/cli/install/supervisor-install.js +158 -0
  211. package/dist/cli/install/supervisor-locate.d.ts +47 -0
  212. package/dist/cli/install/supervisor-locate.d.ts.map +1 -0
  213. package/dist/cli/install/supervisor-locate.js +113 -0
  214. package/dist/cli/install/supervisor-pins.d.ts +21 -0
  215. package/dist/cli/install/supervisor-pins.d.ts.map +1 -0
  216. package/dist/cli/install/supervisor-pins.js +28 -0
  217. package/dist/cli/install/supervisor-record.d.ts +31 -0
  218. package/dist/cli/install/supervisor-record.d.ts.map +1 -0
  219. package/dist/cli/install/supervisor-record.js +104 -0
  220. package/dist/cli/install/supervisor-report.d.ts +11 -0
  221. package/dist/cli/install/supervisor-report.d.ts.map +1 -0
  222. package/dist/cli/install/supervisor-report.js +33 -0
  223. package/dist/cli/install/supervisor-tools.d.ts +43 -0
  224. package/dist/cli/install/supervisor-tools.d.ts.map +1 -0
  225. package/dist/cli/install/supervisor-tools.js +114 -0
  226. package/dist/cli/install/unpack.d.ts +23 -3
  227. package/dist/cli/install/unpack.d.ts.map +1 -1
  228. package/dist/cli/install/unpack.js +124 -10
  229. package/dist/cli/install/zip-member.d.ts +15 -0
  230. package/dist/cli/install/zip-member.d.ts.map +1 -0
  231. package/dist/cli/install/zip-member.js +77 -0
  232. package/dist/cli/interrupt.d.ts +1 -1
  233. package/dist/cli/interrupt.d.ts.map +1 -1
  234. package/dist/cli/interrupt.js +15 -10
  235. package/dist/cli/terminal.d.ts +9 -1
  236. package/dist/cli/terminal.d.ts.map +1 -1
  237. package/dist/cli/terminal.js +14 -0
  238. package/dist/config/define.d.ts +2 -2
  239. package/dist/config/define.js +2 -2
  240. package/dist/config/loaded.d.ts +12 -2
  241. package/dist/config/loaded.d.ts.map +1 -1
  242. package/dist/config/read-inboxes.d.ts +10 -0
  243. package/dist/config/read-inboxes.d.ts.map +1 -0
  244. package/dist/config/read-inboxes.js +78 -0
  245. package/dist/config/register.d.ts +5 -1
  246. package/dist/config/register.d.ts.map +1 -1
  247. package/dist/config/types.d.ts +36 -0
  248. package/dist/config/types.d.ts.map +1 -1
  249. package/dist/config/validate.d.ts.map +1 -1
  250. package/dist/config/validate.js +4 -1
  251. package/dist/diagnostics/artifact.d.ts.map +1 -1
  252. package/dist/diagnostics/artifact.js +10 -2
  253. package/dist/diagnostics/attempt.d.ts +5 -0
  254. package/dist/diagnostics/attempt.d.ts.map +1 -1
  255. package/dist/diagnostics/attempt.js +10 -0
  256. package/dist/diagnostics/chromium-collector.d.ts +9 -1
  257. package/dist/diagnostics/chromium-collector.d.ts.map +1 -1
  258. package/dist/diagnostics/chromium-collector.js +19 -4
  259. package/dist/diagnostics/firefox-collector.d.ts +11 -10
  260. package/dist/diagnostics/firefox-collector.d.ts.map +1 -1
  261. package/dist/diagnostics/firefox-collector.js +16 -11
  262. package/dist/diagnostics/observations.d.ts +8 -0
  263. package/dist/diagnostics/observations.d.ts.map +1 -1
  264. package/dist/diagnostics/session-capture.d.ts.map +1 -1
  265. package/dist/diagnostics/session-capture.js +8 -0
  266. package/dist/index.d.ts +9 -4
  267. package/dist/index.d.ts.map +1 -1
  268. package/dist/index.js +1 -0
  269. package/dist/media/client.d.ts +2 -1
  270. package/dist/media/client.d.ts.map +1 -1
  271. package/dist/media/client.js +16 -5
  272. package/dist/media/host.d.ts +32 -0
  273. package/dist/media/host.d.ts.map +1 -0
  274. package/dist/media/host.js +50 -0
  275. package/dist/media/locate.d.ts.map +1 -1
  276. package/dist/media/locate.js +4 -3
  277. package/dist/media/policy.d.ts +2 -2
  278. package/dist/media/policy.d.ts.map +1 -1
  279. package/dist/media/policy.js +1 -1
  280. package/dist/native/processes.d.ts.map +1 -1
  281. package/dist/native/processes.js +7 -3
  282. package/dist/playwright/not-yet.d.ts.map +1 -1
  283. package/dist/playwright/not-yet.js +5 -2
  284. package/dist/protocol/commands.d.ts +122 -13
  285. package/dist/protocol/commands.d.ts.map +1 -1
  286. package/dist/protocol/commands.js +85 -6
  287. package/dist/protocol/diagnostics.d.ts +10 -0
  288. package/dist/protocol/diagnostics.d.ts.map +1 -1
  289. package/dist/protocol/diagnostics.js +5 -0
  290. package/dist/protocol/dialogs.d.ts +104 -0
  291. package/dist/protocol/dialogs.d.ts.map +1 -0
  292. package/dist/protocol/dialogs.js +101 -0
  293. package/dist/protocol/drag.d.ts +45 -0
  294. package/dist/protocol/drag.d.ts.map +1 -0
  295. package/dist/protocol/drag.js +31 -0
  296. package/dist/protocol/events.d.ts +153 -1
  297. package/dist/protocol/events.d.ts.map +1 -1
  298. package/dist/protocol/events.js +97 -0
  299. package/dist/protocol/files.d.ts +83 -0
  300. package/dist/protocol/files.d.ts.map +1 -0
  301. package/dist/protocol/files.js +73 -0
  302. package/dist/protocol/inbox.d.ts +87 -0
  303. package/dist/protocol/inbox.d.ts.map +1 -0
  304. package/dist/protocol/inbox.js +51 -0
  305. package/dist/protocol/index.d.ts +4 -1
  306. package/dist/protocol/index.d.ts.map +1 -1
  307. package/dist/protocol/layout-checks.d.ts +83 -0
  308. package/dist/protocol/layout-checks.d.ts.map +1 -0
  309. package/dist/protocol/layout-checks.js +214 -0
  310. package/dist/protocol/layout.d.ts +135 -0
  311. package/dist/protocol/layout.d.ts.map +1 -0
  312. package/dist/protocol/layout.js +124 -0
  313. package/dist/protocol/locator-checks.d.ts +19 -2
  314. package/dist/protocol/locator-checks.d.ts.map +1 -1
  315. package/dist/protocol/locator-checks.js +23 -1
  316. package/dist/protocol/locator.d.ts +55 -7
  317. package/dist/protocol/locator.d.ts.map +1 -1
  318. package/dist/protocol/locator.js +99 -18
  319. package/dist/protocol/messages.d.ts +95 -0
  320. package/dist/protocol/messages.d.ts.map +1 -1
  321. package/dist/protocol/messages.js +63 -0
  322. package/dist/protocol/popups.d.ts +43 -0
  323. package/dist/protocol/popups.d.ts.map +1 -0
  324. package/dist/protocol/popups.js +27 -0
  325. package/dist/protocol/result.d.ts +5 -0
  326. package/dist/protocol/result.d.ts.map +1 -1
  327. package/dist/protocol/result.js +1 -0
  328. package/dist/protocol/routes.d.ts +136 -0
  329. package/dist/protocol/routes.d.ts.map +1 -0
  330. package/dist/protocol/routes.js +191 -0
  331. package/dist/protocol/screenshot.d.ts +219 -0
  332. package/dist/protocol/screenshot.d.ts.map +1 -0
  333. package/dist/protocol/screenshot.js +335 -0
  334. package/dist/reporters/actions.d.ts +6 -4
  335. package/dist/reporters/actions.d.ts.map +1 -1
  336. package/dist/reporters/actions.js +24 -6
  337. package/dist/reporters/agent.d.ts.map +1 -1
  338. package/dist/reporters/agent.js +4 -2
  339. package/dist/reporters/commands.d.ts +12 -3
  340. package/dist/reporters/commands.d.ts.map +1 -1
  341. package/dist/reporters/commands.js +29 -11
  342. package/dist/reporters/dialogs-popups.d.ts +22 -0
  343. package/dist/reporters/dialogs-popups.d.ts.map +1 -0
  344. package/dist/reporters/dialogs-popups.js +30 -0
  345. package/dist/reporters/failure-card.d.ts +10 -1
  346. package/dist/reporters/failure-card.d.ts.map +1 -1
  347. package/dist/reporters/failure-card.js +5 -1
  348. package/dist/reporters/format.d.ts +33 -0
  349. package/dist/reporters/format.d.ts.map +1 -1
  350. package/dist/reporters/format.js +42 -0
  351. package/dist/reporters/html/comparison-view.d.ts +12 -0
  352. package/dist/reporters/html/comparison-view.d.ts.map +1 -0
  353. package/dist/reporters/html/comparison-view.js +21 -0
  354. package/dist/reporters/html/diagnostics-view.js +8 -0
  355. package/dist/reporters/html/downloads-view.d.ts +10 -0
  356. package/dist/reporters/html/downloads-view.d.ts.map +1 -0
  357. package/dist/reporters/html/downloads-view.js +29 -0
  358. package/dist/reporters/html/style.d.ts.map +1 -1
  359. package/dist/reporters/html/style.js +3 -0
  360. package/dist/reporters/html/summary-view.d.ts.map +1 -1
  361. package/dist/reporters/html/summary-view.js +3 -2
  362. package/dist/reporters/html/test-view.d.ts.map +1 -1
  363. package/dist/reporters/html/test-view.js +6 -3
  364. package/dist/reporters/html/timeline-view.d.ts.map +1 -1
  365. package/dist/reporters/html/timeline-view.js +26 -2
  366. package/dist/reporters/human-card.js +11 -1
  367. package/dist/reporters/human.d.ts +3 -1
  368. package/dist/reporters/human.d.ts.map +1 -1
  369. package/dist/reporters/human.js +11 -9
  370. package/dist/reporters/routes.d.ts +9 -0
  371. package/dist/reporters/routes.d.ts.map +1 -0
  372. package/dist/reporters/routes.js +17 -0
  373. package/dist/reporters/style.d.ts +21 -2
  374. package/dist/reporters/style.d.ts.map +1 -1
  375. package/dist/reporters/style.js +11 -2
  376. package/dist/runner/app-server.d.ts +27 -7
  377. package/dist/runner/app-server.d.ts.map +1 -1
  378. package/dist/runner/app-server.js +74 -24
  379. package/dist/runner/child-program.js +10 -0
  380. package/dist/runner/child.js +6 -2
  381. package/dist/runner/contract.d.ts +5 -0
  382. package/dist/runner/contract.d.ts.map +1 -1
  383. package/dist/runner/dialogs.d.ts +71 -0
  384. package/dist/runner/dialogs.d.ts.map +1 -0
  385. package/dist/runner/dialogs.js +189 -0
  386. package/dist/runner/files.d.ts +79 -0
  387. package/dist/runner/files.d.ts.map +1 -0
  388. package/dist/runner/files.js +312 -0
  389. package/dist/runner/inbox-links.d.ts +19 -0
  390. package/dist/runner/inbox-links.d.ts.map +1 -0
  391. package/dist/runner/inbox-links.js +63 -0
  392. package/dist/runner/inbox.d.ts +87 -0
  393. package/dist/runner/inbox.d.ts.map +1 -0
  394. package/dist/runner/inbox.js +340 -0
  395. package/dist/runner/index.d.ts +2 -1
  396. package/dist/runner/index.d.ts.map +1 -1
  397. package/dist/runner/media-leftovers.d.ts +7 -3
  398. package/dist/runner/media-leftovers.d.ts.map +1 -1
  399. package/dist/runner/media-leftovers.js +27 -6
  400. package/dist/runner/native-pool.d.ts.map +1 -1
  401. package/dist/runner/native-pool.js +2 -0
  402. package/dist/runner/observations.d.ts +15 -2
  403. package/dist/runner/observations.d.ts.map +1 -1
  404. package/dist/runner/observations.js +109 -6
  405. package/dist/runner/popups.d.ts +82 -0
  406. package/dist/runner/popups.d.ts.map +1 -0
  407. package/dist/runner/popups.js +236 -0
  408. package/dist/runner/redactor.d.ts.map +1 -1
  409. package/dist/runner/redactor.js +10 -6
  410. package/dist/runner/resources.d.ts +8 -0
  411. package/dist/runner/resources.d.ts.map +1 -1
  412. package/dist/runner/resources.js +12 -1
  413. package/dist/runner/routes.d.ts +23 -0
  414. package/dist/runner/routes.d.ts.map +1 -0
  415. package/dist/runner/routes.js +128 -0
  416. package/dist/runner/run-media.d.ts +6 -0
  417. package/dist/runner/run-media.d.ts.map +1 -1
  418. package/dist/runner/run-media.js +21 -0
  419. package/dist/runner/run-session.d.ts.map +1 -1
  420. package/dist/runner/run-session.js +102 -12
  421. package/dist/runner/run.d.ts.map +1 -1
  422. package/dist/runner/run.js +2 -1
  423. package/dist/runner/running-test.d.ts +35 -0
  424. package/dist/runner/running-test.d.ts.map +1 -1
  425. package/dist/runner/running-test.js +333 -22
  426. package/dist/runner/screenshot-baselines.d.ts +159 -0
  427. package/dist/runner/screenshot-baselines.d.ts.map +1 -0
  428. package/dist/runner/screenshot-baselines.js +357 -0
  429. package/dist/runner/secrets.d.ts +13 -0
  430. package/dist/runner/secrets.d.ts.map +1 -1
  431. package/dist/runner/secrets.js +6 -4
  432. package/dist/runner/target-drivers.d.ts +5 -2
  433. package/dist/runner/target-drivers.d.ts.map +1 -1
  434. package/dist/runner/target-drivers.js +10 -1
  435. package/dist/runner/test-file-process.d.ts +8 -0
  436. package/dist/runner/test-file-process.d.ts.map +1 -1
  437. package/dist/runner/test-file-process.js +26 -3
  438. package/dist/runner/test-pages.d.ts +3 -1
  439. package/dist/runner/test-pages.d.ts.map +1 -1
  440. package/dist/runner/test-pages.js +9 -5
  441. package/dist/schemas/event-v1.schema.json +118873 -6311
  442. package/dist/schemas/result-v1.schema.json +4 -0
  443. package/dist/shared/environment.d.ts +17 -0
  444. package/dist/shared/environment.d.ts.map +1 -0
  445. package/dist/shared/environment.js +27 -0
  446. package/dist/shared/image-diff.d.ts +36 -0
  447. package/dist/shared/image-diff.d.ts.map +1 -0
  448. package/dist/shared/image-diff.js +242 -0
  449. package/dist/shared/metadata-process-worker.js +15 -7
  450. package/dist/shared/metadata-process.d.ts +9 -1
  451. package/dist/shared/metadata-process.d.ts.map +1 -1
  452. package/dist/shared/metadata-process.js +84 -12
  453. package/dist/shared/png.d.ts +35 -0
  454. package/dist/shared/png.d.ts.map +1 -0
  455. package/dist/shared/png.js +251 -0
  456. package/dist/shared/posix-path.d.ts +12 -0
  457. package/dist/shared/posix-path.d.ts.map +1 -1
  458. package/dist/shared/posix-path.js +16 -0
  459. package/dist/shared/private-file.d.ts +38 -0
  460. package/dist/shared/private-file.d.ts.map +1 -0
  461. package/dist/shared/private-file.js +132 -0
  462. package/dist/shared/process-ownership.d.ts +67 -6
  463. package/dist/shared/process-ownership.d.ts.map +1 -1
  464. package/dist/shared/process-ownership.js +227 -45
  465. package/dist/shared/process-supervisor.d.ts +309 -0
  466. package/dist/shared/process-supervisor.d.ts.map +1 -0
  467. package/dist/shared/process-supervisor.js +737 -0
  468. package/dist/shared/process-system.d.ts +113 -0
  469. package/dist/shared/process-system.d.ts.map +1 -0
  470. package/dist/shared/process-system.js +254 -0
  471. package/dist/shared/regular-file.d.ts +2 -2
  472. package/dist/shared/regular-file.d.ts.map +1 -1
  473. package/dist/shared/regular-file.js +19 -2
  474. package/dist/store/artifacts.d.ts +28 -6
  475. package/dist/store/artifacts.d.ts.map +1 -1
  476. package/dist/store/artifacts.js +58 -6
  477. package/dist/store/rebuild-result.d.ts.map +1 -1
  478. package/dist/store/rebuild-result.js +6 -0
  479. package/dist/store/run-store.d.ts +5 -2
  480. package/dist/store/run-store.d.ts.map +1 -1
  481. package/dist/store/run-store.js +48 -4
  482. package/media/Cargo.lock +16 -0
  483. package/media/Cargo.toml +16 -1
  484. package/media/src/encoder.rs +56 -12
  485. package/media/src/frame.rs +7 -1
  486. package/media/src/main.rs +20 -2
  487. package/media/src/place.rs +230 -11
  488. package/media/src/process_ownership_windows.rs +1058 -0
  489. package/media/src/recording.rs +15 -7
  490. package/media/src/replies.rs +55 -0
  491. package/media/src/server.rs +72 -2
  492. package/media/src/store.rs +71 -2
  493. package/package.json +9 -4
  494. package/src/cli/install/media-notices.txt +465 -1
  495. package/supervisor/Cargo.lock +25 -0
  496. package/supervisor/Cargo.toml +22 -0
  497. package/supervisor/NOTICES +464 -0
  498. package/supervisor/build.rs +44 -0
  499. package/supervisor/src/command.rs +612 -0
  500. package/supervisor/src/jobs.rs +1650 -0
  501. package/supervisor/src/main.rs +71 -0
  502. package/supervisor/src/reply.rs +367 -0
@@ -1,7 +1,7 @@
1
1
  import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from 'node:fs';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { access, lstat, readdir, readlink } from 'node:fs/promises';
4
- import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
+ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep, win32 } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { folderChecksum, nativePins, pinKey, readBuildRecord } from "../native/executors.js";
7
7
  import { errorMessage } from "../protocol/failures.js";
@@ -13,6 +13,8 @@ export const buildEngines = ['chromium', 'firefox', 'webkit', 'electron', 'webdr
13
13
  const chromiumVersion = '153.0.8010.12';
14
14
  const chromeForTesting = 'https://storage.googleapis.com/chrome-for-testing-public';
15
15
  const macChrome = 'chrome-mac-arm64/Google Chrome for Testing.app';
16
+ const firefoxReleases = 'https://archive.mozilla.org/pub/firefox/releases';
17
+ const electronReleases = 'https://github.com/electron/electron/releases/download';
16
18
  // Authorized Linux archive observations, retained beside the pin table without adding unsupported install pins.
17
19
  // Firefox 133.0.3: https://archive.mozilla.org/pub/firefox/releases/133.0.3/linux-x86_64/en-US/firefox-133.0.3.tar.bz2
18
20
  // 89_495_132 bytes; SHA-256 43713e238d0153fdbf1ab46dd76c6b01ab83fae197b5dc3a95087f51907ba44d.
@@ -76,6 +78,7 @@ function executorPin(engine) {
76
78
  * The tested set. Chromium is Chrome for Testing, from Google; Firefox is Mozilla's release; WebKit is Playwright's
77
79
  * automation build, the only WebKit build with the inspector pipe Retest drives; Electron is the release its fixture app
78
80
  * runs on; the two native executors are built from their pinned commits. Only Chromium is pinned for Linux x64; its archive has been inspected, without a Linux browser execution claim.
81
+ * Windows x64 has Chromium, Firefox and Electron, from the same releases, and no WebKit build.
79
82
  */
80
83
  export const pinnedBuilds = [
81
84
  {
@@ -114,23 +117,58 @@ export const pinnedBuilds = [
114
117
  },
115
118
  provenance: 'Archive size and checksum, executable and both licence files read from the Google publisher download. Linux browser execution and installation remain unverified.',
116
119
  },
120
+ {
121
+ kind: 'archive',
122
+ engine: 'chromium',
123
+ title: 'Chrome for Testing',
124
+ version: chromiumVersion,
125
+ platform: 'win-x64',
126
+ archive: { format: 'zip', url: `${chromeForTesting}/${chromiumVersion}/win64/chrome-win64.zip`, size: 205_123_748, sha256: '415968b02065d4a9e2c10b85f0ae9f489b8fba500e94d9d0a7b7c4852a7234c1' },
127
+ executable: { path: 'chrome-win64/chrome.exe', sha256: '9b07943f834485b43c9d54caea2951c78715f9f07070a80ab6658465ebd3e711' },
128
+ files: [],
129
+ licences: {
130
+ inspected: true,
131
+ files: [
132
+ { path: 'chrome-win64/ABOUT', title: "the build's notice, which names chrome://credits, where the licences compiled into the browser are listed", licence: 'BSD-3-Clause and the licences at chrome://credits', sha256: '122b32f3ee3f1e8d65c774f5257fc6cc2127b666148ced0ce2efa3ea57e1d93c', published: true },
133
+ ],
134
+ },
135
+ provenance: 'Archive size and checksum, executable and notice read from the Google publisher download of 21 October 2026, here and on a Windows Server 2025 machine, whose own tar.exe unpacks the same files as unzip and libarchive bsdtar do on macOS. The Windows build carries no Widevine module, so there is no Widevine licence to pin. Installed by retest install and run on Windows Server 2025 x64, on a GitHub windows-2025 runner, in the 0.3.0 CI matrix.',
136
+ },
117
137
  {
118
138
  kind: 'archive',
119
139
  engine: 'firefox',
120
140
  title: 'Firefox',
121
- version: '133.0.3',
122
- build: '20241209150345',
141
+ version: '158.0.1',
142
+ build: '20261019185856',
123
143
  platform: 'mac-arm64',
124
- archive: { format: 'dmg', app: 'Firefox.app', url: 'https://archive.mozilla.org/pub/firefox/releases/133.0.3/mac/en-US/Firefox%20133.0.3.dmg', size: 154_008_053, sha256: '9ceb4fa2120228f287e6c654cef7898b4cce0a659270056276b8884581267d3b', checksums: 'https://archive.mozilla.org/pub/firefox/releases/133.0.3/SHA256SUMS' },
125
- executable: { path: 'Firefox.app/Contents/MacOS/firefox', sha256: '363eae026f4f5b3a8549f6a9c96a269754094ef12afc5f02cdffbcb4bcbf389c' },
144
+ archive: { format: 'dmg', app: 'Firefox.app', url: `${firefoxReleases}/158.0.1/mac/en-US/Firefox%20158.0.1.dmg`, size: 165_038_147, sha256: '1d7aa96b51fc9110185047de18228ac87238fba5e42bba53c9d696f88878cba6', checksums: `${firefoxReleases}/158.0.1/SHA256SUMS` },
145
+ executable: { path: 'Firefox.app/Contents/MacOS/firefox', sha256: '0b406e1d7c88d48c13f6389e05f22dedcb6ab99f06e539150a49e4ba995d0386' },
126
146
  files: [],
127
147
  licences: {
128
148
  inspected: true,
129
149
  files: [
130
- { path: 'Firefox.app/Contents/Resources/omni.ja', title: "the archive that holds Firefox's about:license page, chrome/toolkit/content/global/license.html", licence: 'MPL-2.0 and the licences at about:license', sha256: '1ecdc0a4f6de9f562b24417cdaff4d2f17474d51572e65bbc4c7489cf4025c38', published: true },
150
+ { path: 'Firefox.app/Contents/Resources/omni.ja', title: "the archive that holds Firefox's about:license page, chrome/toolkit/content/global/license.html", licence: 'MPL-2.0 and the licences at about:license', sha256: 'dbfea026a6155b5c8794f55b2e54b19b0120353379a18e343dad381aa84228f5', published: true },
131
151
  ],
132
152
  },
133
- provenance: 'Version, build id, executable and omni.ja checksums originally read from the signed en-US Firefox 133.0.3 in /Applications. The Mozilla disk-image download carries the same executable and omni.ja. The image holds Firefox.app at its root, copied to Firefox.app under the installed build. The archive size and checksum pinned above were measured from that download, which unpacked as the pin describes. Mozilla SHA256SUMS was not fetched for this pin.',
153
+ provenance: "Archive size and checksum from Mozilla's download of 22 October 2026, which matched the release's SHA256SUMS. The image holds Firefox.app at its root, copied to Firefox.app under the installed build. Executable and omni.ja checksums read from the mounted image; its application.ini names Firefox 158.0.1 build 20261019185856.",
154
+ },
155
+ {
156
+ kind: 'archive',
157
+ engine: 'firefox',
158
+ title: 'Firefox',
159
+ version: '158.0.1',
160
+ build: '20261019185856',
161
+ platform: 'win-x64',
162
+ archive: { format: 'exe', folder: 'core', url: `${firefoxReleases}/158.0.1/win64/en-US/Firefox%20Setup%20158.0.1.exe`, size: 94_890_968, sha256: '3259a2f8508e58cf2e383b6c99bfc64d6ddc86d1407b7c2f86f660af955b5d10', checksums: `${firefoxReleases}/158.0.1/SHA256SUMS` },
163
+ executable: { path: 'core/firefox.exe', sha256: '76732d4e43c864194660c671c52ecf4bad89e43b666d9a0acf89cd4b692ced9b' },
164
+ files: [],
165
+ licences: {
166
+ inspected: true,
167
+ files: [
168
+ { path: 'core/omni.ja', title: "the archive that holds Firefox's about:license page, chrome/toolkit/content/global/license.html", licence: 'MPL-2.0 and the licences at about:license', sha256: '42f976ac57103698320728a9c134ec8e710ab9a3c48d127ea3e115e1b3b211c3', published: true },
169
+ ],
170
+ },
171
+ provenance: "Archive size and checksum from Mozilla's download of 22 October 2026, which matched the release's SHA256SUMS. Mozilla publishes no zip of a Windows release, only this installer: a 7-Zip archive behind a self-extracting stub that Retest never runs. The archive holds setup.exe and the core folder, which is the whole of Firefox and is unpacked alone. Executable and omni.ja checksums read from that folder as libarchive bsdtar unpacked it on macOS, and the same bytes again after retest install unpacked it with tar.exe on a Windows Server 2025 machine; its application.ini names Firefox 158.0.1 build 20261019185856.",
134
172
  },
135
173
  {
136
174
  kind: 'archive',
@@ -171,6 +209,25 @@ export const pinnedBuilds = [
171
209
  treeSha256: 'f94a2b748b5f3e41b0ff1938ebd02052bb8af4cf037c2d24d21ffd51c5f7d7b4',
172
210
  provenance: "Archive size and checksum from a download of the official release, which matched the release's SHASUMS256.txt; executable, licence and tree checksums read from that archive unpacked with ditto in ~/Library/Caches/retest-proofs/electron/44.5.1.",
173
211
  },
212
+ {
213
+ kind: 'archive',
214
+ engine: 'electron',
215
+ title: 'Electron',
216
+ version: '44.5.1',
217
+ platform: 'win-x64',
218
+ archive: { format: 'zip', url: `${electronReleases}/v44.5.1/electron-v44.5.1-win32-x64.zip`, size: 157_998_329, sha256: '9b382492dcfee91f8f9e92c91f7972550a1b95d2299cac72279dab33a600d7db', checksums: `${electronReleases}/v44.5.1/SHASUMS256.txt` },
219
+ executable: { path: 'electron.exe', sha256: '49b61a030a520fc36a4b8fa5cce53fb4e935a7bdbbe4b80e9222f598e49cc7fa' },
220
+ files: [],
221
+ licences: {
222
+ inspected: true,
223
+ files: [
224
+ { path: 'LICENSE', title: "Electron's licence", licence: 'MIT', sha256: '5154e165bd6c2cc0cfbcd8916498c7abab0497923bafcd5cb07673fe8480087d', published: true },
225
+ { path: 'LICENSES.chromium.html', title: 'the licences of Chromium and the libraries compiled into it', licence: 'BSD-3-Clause and the licences it lists', sha256: '7b328b8c7463ac9bfc7dc648c751533517c8441a0b5b21047d6c0b2620e60d70', published: true },
226
+ ],
227
+ },
228
+ treeSha256: '0a50669f7461801821ab9d01ee2193748d36f45b6235bcfd648ed9a44a175e30',
229
+ provenance: "Archive size and checksum from a download of the official release on 21 October 2026, which matched the release's SHASUMS256.txt, here and on a Windows Server 2025 machine. Executable, licence and tree checksums read on that machine from the archive unpacked with its own tar.exe; unzip and libarchive bsdtar on macOS unpack the same files. Installed by retest install and run on Windows Server 2025 x64, on a GitHub windows-2025 runner, in the 0.3.0 CI matrix.",
230
+ },
174
231
  executorPin('webdriveragent'),
175
232
  executorPin('mac2'),
176
233
  ];
@@ -184,11 +241,14 @@ export function buildPlatform(platform = process.platform, arch = process.arch)
184
241
  return 'mac-arm64';
185
242
  if (platform === 'linux' && arch === 'x64')
186
243
  return 'linux-x64';
244
+ if (platform === 'win32' && arch === 'x64')
245
+ return 'win-x64';
187
246
  return undefined;
188
247
  }
189
- /** @example describePlatform('linux-x64') // 'Linux x64' */
248
+ const platformNames = { 'mac-arm64': 'macOS arm64', 'linux-x64': 'Linux x64', 'win-x64': 'Windows x64' };
249
+ /** @example describePlatform('win-x64') // 'Windows x64' */
190
250
  export function describePlatform(platform) {
191
- return platform === 'mac-arm64' ? 'macOS arm64' : 'Linux x64';
251
+ return platformNames[platform];
192
252
  }
193
253
  /**
194
254
  * The pin of one engine for one platform, if Retest pins one.
@@ -198,6 +258,16 @@ export function describePlatform(platform) {
198
258
  export function findPin(engine, platform, pins = pinnedBuilds) {
199
259
  return pins.find((pin) => pin.engine === engine && pin.platform === platform);
200
260
  }
261
+ /**
262
+ * Why there is no pin of an engine for a platform, as one sentence for `retest install` to refuse with.
263
+ *
264
+ * @example unpinnedMessage('webkit', 'win-x64') // 'Retest does not run WebKit on Windows, so there is no WebKit build to install.'
265
+ */
266
+ export function unpinnedMessage(engine, platform) {
267
+ if (engine === 'webkit' && platform === 'win-x64')
268
+ return 'Retest does not run WebKit on Windows, so there is no WebKit build to install.';
269
+ return `Retest pins no ${engine} build for ${describePlatform(platform)}.`;
270
+ }
201
271
  /** @example describePin(findPin('electron', 'mac-arm64')) // 'Electron 44.5.1' */
202
272
  export function describePin(pin) {
203
273
  const build = pin.kind === 'archive' && pin.build !== undefined ? ` (build ${pin.build})` : '';
@@ -275,17 +345,46 @@ export function readBundledLicence(file) {
275
345
  }
276
346
  /**
277
347
  * The cache folders under the user's cache folder: `~/Library/Caches/retest` on macOS, `$XDG_CACHE_HOME/retest` or
278
- * `~/.cache/retest` on Linux. Undefined without an absolute `HOME`, since there is then no user cache folder.
348
+ * `~/.cache/retest` on Linux, `%LOCALAPPDATA%\retest` on Windows. Undefined without an absolute `HOME`, or on Windows
349
+ * an absolute `LOCALAPPDATA`, since there is then no user cache folder. Paths are written as `platform` writes them.
279
350
  *
280
351
  * @example cacheFolders({ HOME: '/Users/ada' }, 'darwin')?.browsers // '/Users/ada/Library/Caches/retest/browsers'
352
+ * @example cacheFolders({ LOCALAPPDATA: 'C:\\Users\\ada\\AppData\\Local' }, 'win32')?.browsers // 'C:\\Users\\ada\\AppData\\Local\\retest\\browsers'
281
353
  */
282
354
  export function cacheFolders(env, platform = process.platform) {
355
+ if (platform === 'win32') {
356
+ const local = environmentVariable(env, cacheVariable(platform), platform);
357
+ if (local === undefined || !win32.isAbsolute(local))
358
+ return undefined;
359
+ return { browsers: win32.join(local, 'retest', 'browsers'), executors: win32.join(local, 'retest', 'native-executors') };
360
+ }
283
361
  const home = env['HOME'];
284
- if (home === undefined || !isAbsolute(home))
362
+ if (home === undefined || !posix.isAbsolute(home))
285
363
  return undefined;
286
364
  const xdg = env['XDG_CACHE_HOME'];
287
- const root = platform === 'darwin' ? join(home, 'Library', 'Caches') : xdg !== undefined && isAbsolute(xdg) ? xdg : join(home, '.cache');
288
- return { browsers: join(root, 'retest', 'browsers'), executors: join(root, 'retest', 'native-executors') };
365
+ const root = platform === 'darwin' ? posix.join(home, 'Library', 'Caches') : xdg !== undefined && posix.isAbsolute(xdg) ? xdg : posix.join(home, '.cache');
366
+ return { browsers: posix.join(root, 'retest', 'browsers'), executors: posix.join(root, 'retest', 'native-executors') };
367
+ }
368
+ /**
369
+ * The variable `cacheFolders` finds the user's cache folder from, for a message to name when it is not set.
370
+ *
371
+ * @example cacheVariable('win32') // 'LOCALAPPDATA'
372
+ */
373
+ export function cacheVariable(platform = process.platform) {
374
+ return platform === 'win32' ? 'LOCALAPPDATA' : 'HOME';
375
+ }
376
+ /**
377
+ * An environment variable as the system reads it: by its exact name, and on Windows, where names differ only in case
378
+ * for the same variable, by any spelling of it. `process.env` already reads so on Windows; a copy of it does not.
379
+ *
380
+ * @example environmentVariable({ ProgramFiles: 'C:\\Program Files' }, 'PROGRAMFILES', 'win32') // 'C:\\Program Files'
381
+ */
382
+ export function environmentVariable(env, name, platform = process.platform) {
383
+ const exact = env[name];
384
+ if (exact !== undefined || platform !== 'win32')
385
+ return exact;
386
+ const wanted = name.toUpperCase();
387
+ return Object.entries(env).find(([key]) => key.toUpperCase() === wanted)?.[1];
289
388
  }
290
389
  /**
291
390
  * The folder one pin's build is installed in. A browser or Electron build is named after its engine, version and
@@ -315,7 +414,7 @@ const installedRecordSchema = s.object({
315
414
  schemaVersion: s.literal(1),
316
415
  engine: s.enum(['chromium', 'firefox', 'webkit', 'electron']),
317
416
  version: s.string(),
318
- platform: s.enum(['mac-arm64', 'linux-x64']),
417
+ platform: s.enum(['mac-arm64', 'linux-x64', 'win-x64']),
319
418
  source: s.string(),
320
419
  sourceCode: s.optional(s.object({ repository: s.string(), revision: s.string(), patches: s.string() })),
321
420
  fetchedFrom: s.string(),
@@ -483,7 +582,7 @@ export async function inspectBuilds(platform, folders, options = {}, pins = pinn
483
582
  * `retest install` refuses. The message names the folder, what is wrong and how to fix it. Nothing is downloaded,
484
583
  * and nothing is thrown: a folder that cannot be read is damaged.
485
584
  *
486
- * @example await installedBuild('firefox', process.env) // { state: 'damaged', message: 'Firefox 133.0.3 … in … is not usable: …' }
585
+ * @example await installedBuild('firefox', process.env) // { state: 'damaged', message: 'Firefox 158.0.1 … in … is not usable: …' }
487
586
  */
488
587
  export async function installedBuild(engine, env, options = {}) {
489
588
  const platform = 'platform' in options ? options.platform : buildPlatform();
@@ -511,7 +610,7 @@ export async function installedBuild(engine, env, options = {}) {
511
610
  * installed as its pin and record say; undefined otherwise, which a damaged build is too. A driver that must tell a
512
611
  * damaged build from a missing one asks `installedBuild`. A target's own `executablePath` always wins over it.
513
612
  *
514
- * @example await installedExecutable('firefox', process.env) // '/Users/ada/Library/Caches/retest/browsers/firefox-133.0.3-mac-arm64/build/Firefox.app/Contents/MacOS/firefox'
613
+ * @example await installedExecutable('firefox', process.env) // '/Users/ada/Library/Caches/retest/browsers/firefox-158.0.1-mac-arm64/build/Firefox.app/Contents/MacOS/firefox'
515
614
  */
516
615
  export async function installedExecutable(engine, env, options = {}) {
517
616
  const build = await installedBuild(engine, env, options);
@@ -51,6 +51,12 @@ export declare class CdpConnection {
51
51
  * @example const session = await connection.attach(targetId)
52
52
  */
53
53
  attach(targetId: string, options?: SendOptions): Promise<CdpSession>;
54
+ /**
55
+ * Takes on a flat session the browser attached by itself, as `Target.setAutoAttach` does, named in its
56
+ * `Target.attachedToTarget` event. Call it while that event is handled, so no event of the session's arrives first.
57
+ * @example const session = connection.adopt(sessionId)
58
+ */
59
+ adopt(sessionId: string): CdpSession;
54
60
  /** Ends the connection. Every waiting command rejects with a `CdpDisconnectedError`. */
55
61
  close(): void;
56
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/browser/cdp/connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAehE,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAE3D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAA;CAClD,CAAA;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAa,CAAA;AAc/C,2DAA2D;AAC3D,qBAAa,aAAa;;gBAWZ,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB;IAkB5D,qCAAqC;IACrC,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9E;;;OAGG;IACH,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAInE,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAI5D;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAMpE,wFAAwF;IACxF,KAAK,IAAI,IAAI;CAkKd"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/browser/cdp/connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAehE,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAE3D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAA;CAClD,CAAA;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAa,CAAA;AAc/C,2DAA2D;AAC3D,qBAAa,aAAa;;gBAWZ,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB;IAkB5D,qCAAqC;IACrC,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9E;;;OAGG;IACH,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAInE,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAI5D;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAMpE;;;;OAIG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU;IAIpC,wFAAwF;IACxF,KAAK,IAAI,IAAI;CAkKd"}
@@ -62,6 +62,14 @@ export class CdpConnection {
62
62
  attach(targetId, options) {
63
63
  return this.#send(this.#root, ATTACH_METHOD, { targetId, flatten: true }, options, (result) => this.#openSession(result));
64
64
  }
65
+ /**
66
+ * Takes on a flat session the browser attached by itself, as `Target.setAutoAttach` does, named in its
67
+ * `Target.attachedToTarget` event. Call it while that event is handled, so no event of the session's arrives first.
68
+ * @example const session = connection.adopt(sessionId)
69
+ */
70
+ adopt(sessionId) {
71
+ return this.#openSession({ sessionId });
72
+ }
65
73
  /** Ends the connection. Every waiting command rejects with a `CdpDisconnectedError`. */
66
74
  close() {
67
75
  this.#transport.close();
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/browser/cdp/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,iEAAiE;IACjE,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,sDAAsD;IACtD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,IAAI,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACzC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;IACnC,KAAK,IAAI,IAAI,CAAA;CACd;AAED,uFAAuF;AACvF,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAA;AAMpE,6EAA6E;AAC7E,qBAAa,aAAc,YAAW,SAAS;;gBAUjC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,WAAW;IAiB/C,qFAAqF;IACrF,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAUzC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAgBnC,KAAK,IAAI,IAAI;CAqDd"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/browser/cdp/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,iEAAiE;IACjE,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,sDAAsD;IACtD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,IAAI,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACzC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;IACnC,KAAK,IAAI,IAAI,CAAA;CACd;AAED,uFAAuF;AACvF,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAA;AAMpE,6EAA6E;AAC7E,qBAAa,aAAc,YAAW,SAAS;;gBAUjC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,WAAW;IAkB/C,qFAAqF;IACrF,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAUzC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAgBnC,KAAK,IAAI,IAAI;CAqDd"}
@@ -12,20 +12,20 @@ export class PipeTransport {
12
12
  constructor({ readable, writable }) {
13
13
  this.#readable = readable;
14
14
  this.#writable = writable;
15
+ // A pipe that closes without Retest closing it means the browser went, whichever of its two ends Node hears of first,
16
+ // so a killed browser is told of in one sentence however the ends race.
15
17
  readable.on('end', () => this.#end('the browser closed the pipe'));
16
18
  readable.on('close', () => this.#end('the browser closed the pipe'));
17
19
  readable.on('error', (error) => this.#end(`reading from the browser failed: ${error.message}`));
18
- writable.on('close', () => this.#end('the pipe to the browser closed'));
20
+ writable.on('close', () => this.#end('the browser closed the pipe'));
19
21
  writable.on('error', (error) => this.#end(`writing to the browser failed: ${error.message}`));
20
22
  writable.on('drain', () => {
21
23
  this.#blocked = false;
22
24
  this.#flush();
23
25
  });
24
26
  // A stream that ended before this point never emits its events again.
25
- if (readable.destroyed || readable.readableEnded)
27
+ if (readable.destroyed || readable.readableEnded || writable.destroyed || writable.writableEnded)
26
28
  this.#end('the browser closed the pipe');
27
- else if (writable.destroyed || writable.writableEnded)
28
- this.#end('the pipe to the browser closed');
29
29
  }
30
30
  /** Starts reading. Nothing is read before this, so no message can arrive unheard. */
31
31
  listen(handlers) {
@@ -1,10 +1,10 @@
1
1
  import type { ActionIntent } from './element-queries.ts';
2
- import type { IsolatedWorld } from './isolated-world.ts';
2
+ import type { PageWorld } from './isolated-world.ts';
3
3
  import type { Deadline } from '../protocol/deadline.ts';
4
4
  import type { Failure } from '../protocol/failures.ts';
5
5
  import type { LocatorRecipe } from '../protocol/locator.ts';
6
6
  export type CheckedStateOptions = {
7
- world: IsolatedWorld;
7
+ world: PageWorld;
8
8
  locator: LocatorRecipe;
9
9
  intent: Extract<ActionIntent, {
10
10
  action: 'check' | 'uncheck';
@@ -1 +1 @@
1
- {"version":3,"file":"checked-state.d.ts","sourceRoot":"","sources":["../../src/browser/checked-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAM3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,aAAa,CAAA;IACpB,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE;QAAE,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,CAAC,CAAA;IAC9D,4DAA4D;IAC5D,GAAG,EAAE,OAAO,GAAG,SAAS,CAAA;IACxB,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAKD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAgBpI"}
1
+ {"version":3,"file":"checked-state.d.ts","sourceRoot":"","sources":["../../src/browser/checked-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAM3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE;QAAE,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,CAAC,CAAA;IAC9D,4DAA4D;IAC5D,GAAG,EAAE,OAAO,GAAG,SAAS,CAAA;IACxB,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAKD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAgBpI"}
@@ -70,10 +70,17 @@ export declare class ChromiumProcess {
70
70
  */
71
71
  gone(): Promise<void>;
72
72
  /**
73
- * Reads descendants while their launched parent is still present: when the connection drops and before asking the
74
- * parent to quit. A helper recorded early is still owned after its parent dies.
73
+ * Reads descendants while their launched parent is still present, holding the thread, as a process made from a
74
+ * child no owner has read yet does. A helper recorded early is still owned after its parent dies.
75
75
  */
76
76
  recordDescendants(deadline?: Deadline): void;
77
+ /**
78
+ * `recordDescendants` from a reading begun now that does not hold the thread, within `deadline`, as a close reads
79
+ * before it asks the browser to quit. A reading that fails is kept, as one that holds the thread is.
80
+ *
81
+ * @example await chromium.recordDescendantsNow(new Deadline(5000))
82
+ */
83
+ recordDescendantsNow(deadline: Deadline): Promise<void>;
77
84
  /**
78
85
  * `recordDescendants` from a reading taken without holding the thread, as after each new page, whose renderer the
79
86
  * browser has just started. A process-table reading takes tens of milliseconds, which a page open would otherwise wait.
@@ -105,4 +112,27 @@ export declare function stillThereMessage(groupId: number, stats: () => readonly
105
112
  export declare function signalGroup(pgid: number, signal: NodeJS.Signals | 0): boolean;
106
113
  /** Signals a descendant only after this process recorded it beneath the launched browser. */
107
114
  export declare function signalRecordedProcess(browserPid: number, pid: number, signal: NodeJS.Signals): void;
115
+ /**
116
+ * Waits for the output to close. A timer can fire before I/O that is already waiting has been read, when the main thread
117
+ * was busy with other work such as synchronous process readings, so the clock alone is no proof the output is still
118
+ * open: on a busy host every healthy close failed so. When the bound passes, waiting I/O is read first, then the output
119
+ * is judged by whether anything can still write to it. Once nothing can, Retest's own writing gets its own bound.
120
+ * If a writer remains after verified owned shutdown, an output with safe reader finish support may stop its local
121
+ * readers and flush accepted bytes and queued writes within that same writing bound. This does not claim remote
122
+ * EOF or collect bytes an inherited writer sends later. An output without this support still fails and is canceled.
123
+ */
124
+ export declare function outputWithin(output: BrowserOutput, timeoutMs: number, confirmedGone: () => Promise<boolean>): Promise<string[]>;
125
+ /** How long an exit hook on Windows asks again to remove a folder whose processes it confirmed gone. */
126
+ export declare const exitRemovalMs: number;
127
+ /**
128
+ * Removes a folder from an exit hook on Windows, where a folder whose files processes just ended were using refuses
129
+ * removal for a moment after they left their job, and the synchronous removal does not wait: it is asked again, a poll
130
+ * apart, until the deadline.
131
+ */
132
+ export declare function removeOnceFree(folder: string, deadline: Deadline): void;
133
+ /**
134
+ * Whether a group is gone, for an exit hook, which cannot await. Processes just sent SIGKILL are still exiting when they
135
+ * are first read, so the group is read again, a poll apart, until it is gone or the deadline passes.
136
+ */
137
+ export declare function groupEndsNow(ownership: OwnedProcessGroup, deadline: Deadline): boolean;
108
138
  //# sourceMappingURL=chromium-process.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chromium-process.d.ts","sourceRoot":"","sources":["../../src/browser/chromium-process.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chromium-process.d.ts","sourceRoot":"","sources":["../../src/browser/chromium-process.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAQnD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAMlD,OAAO,EAAE,iBAAiB,EAA4B,MAAM,gCAAgC,CAAA;AAE5F,OAAO,EAAgB,WAAW,EAAE,MAAM,eAAe,CAAA;AAGzD,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAA;IACf,sDAAsD;IACtD,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,+FAA+F;IAC/F,YAAY,CAAC,EAAE,MAAM,cAAc,CAAA;CACpC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAClC,MAAM,IAAI,IAAI,CAAA;IACd,4GAA4G;IAC5G,aAAa,CAAC,IAAI,IAAI,CAAA;IACtB,aAAa,CAAC,IAAI,OAAO,CAAA;CAC1B,CAAA;AAYD,iHAAiH;AACjH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;gBACzB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,YAAY,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAAA;KAAE,EAAE,aAAa,GAAE,OAAO,CAAC,IAAI,CAAQ;CAKrK;AAED,sGAAsG;AACtG,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IACrC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAUrC;;;;OAIG;WACU,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;gBAcvD,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAE,aAAwE,EAAE,SAAS,CAAC,EAAE,iBAAiB;IAuBhM;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBrB;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,GAAE,QAAqC,GAAG,IAAI;IAIxE;;;;;OAKG;IACG,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;OAGG;IACH,qBAAqB,IAAI,IAAI;IAQ7B,uGAAuG;IACjG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAStE;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAyE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAiE9H;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,MAAM,EAAE,EAAE,SAAS,GAAE,MAAqB,GAAG,MAAM,CAI3H;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,CA+B7E;AAED,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAKnG;AAmFD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBrI;AAqCD,wGAAwG;AACxG,eAAO,MAAM,aAAa,EAAE,MAAyB,CAAA;AAmBrD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAYvE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAOtF"}
@@ -2,15 +2,17 @@ import { spawn } from 'node:child_process';
2
2
  import { once } from 'node:events';
3
3
  import { rmSync } from 'node:fs';
4
4
  import { mkdir, open, rm } from 'node:fs/promises';
5
- import { dirname } from 'node:path';
5
+ import { basename, dirname } from 'node:path';
6
6
  import { Readable, Writable } from 'node:stream';
7
7
  import { setTimeout as sleep } from 'node:timers/promises';
8
8
  import { Deadline } from "../protocol/deadline.js";
9
9
  import { maxTimeout } from "../protocol/timeouts.js";
10
10
  import { errorMessage } from "../protocol/failures.js";
11
+ import { withoutVariables } from "../shared/environment.js";
11
12
  import { errorCode } from "../shared/error-code.js";
12
13
  import { onlyUnreaped, procStats } from "../shared/unreaped-group.js";
13
14
  import { OwnedProcessGroup, unverifiedMembersProblem } from "../shared/process-ownership.js";
15
+ import { holdLaunch, launchesHeldByJob, prepareOwnedLaunch } from "../shared/process-system.js";
14
16
  import { closeGraceMs, LaunchError } from "./contract.js";
15
17
  import { writeRedactedLog } from "./redacted-log.js";
16
18
  const pollMs = 25;
@@ -86,7 +88,10 @@ export class ChromiumProcess {
86
88
  resolve(this.#exit);
87
89
  });
88
90
  });
89
- this.recordDescendants();
91
+ // A launch hands over the owner it has just read. Reading it again at once found nothing new, and on a loaded host
92
+ // that second reading outlasted its second and failed the browser's close however cleanly it later ended.
93
+ if (!this.#ownership.captured)
94
+ this.recordDescendants();
90
95
  this.#lastResort = () => killAtExit(this.#ownership, profile);
91
96
  process.on('exit', this.#lastResort);
92
97
  }
@@ -116,12 +121,21 @@ export class ChromiumProcess {
116
121
  await this.#output.closed;
117
122
  }
118
123
  /**
119
- * Reads descendants while their launched parent is still present: when the connection drops and before asking the
120
- * parent to quit. A helper recorded early is still owned after its parent dies.
124
+ * Reads descendants while their launched parent is still present, holding the thread, as a process made from a
125
+ * child no owner has read yet does. A helper recorded early is still owned after its parent dies.
121
126
  */
122
127
  recordDescendants(deadline = new Deadline(closeGraceMs)) {
123
128
  this.#keep(this.#ownership.capture(deadline));
124
129
  }
130
+ /**
131
+ * `recordDescendants` from a reading begun now that does not hold the thread, within `deadline`, as a close reads
132
+ * before it asks the browser to quit. A reading that fails is kept, as one that holds the thread is.
133
+ *
134
+ * @example await chromium.recordDescendantsNow(new Deadline(5000))
135
+ */
136
+ async recordDescendantsNow(deadline) {
137
+ this.#keep(await this.#ownership.captureAsync(deadline));
138
+ }
125
139
  /**
126
140
  * `recordDescendants` from a reading taken without holding the thread, as after each new page, whose renderer the
127
141
  * browser has just started. A process-table reading takes tens of milliseconds, which a page open would otherwise wait.
@@ -240,6 +254,22 @@ export function stillThereMessage(groupId, stats, timeoutMs = closeGraceMs) {
240
254
  * @example signalGroup(browser.pid, 0) // true while any browser process is still there
241
255
  */
242
256
  export function signalGroup(pgid, signal) {
257
+ // Windows has no process group to send signal 0 to: a launch held here is asked through its job, and one held by
258
+ // another process only by its own pid.
259
+ if (signal === 0 && launchesHeldByJob) {
260
+ const owner = ownedGroups.get(pgid);
261
+ if (owner !== undefined)
262
+ return owner.remains();
263
+ try {
264
+ process.kill(pgid, 0);
265
+ return true;
266
+ }
267
+ catch (error) {
268
+ if (errorCode(error) === 'ESRCH')
269
+ return false;
270
+ throw error;
271
+ }
272
+ }
243
273
  if (signal !== 0) {
244
274
  const owner = ownedGroups.get(pgid);
245
275
  if (owner === undefined)
@@ -277,18 +307,33 @@ async function spawnInGroup(options) {
277
307
  const log = await openLog(options.logFile);
278
308
  let logHandedOn = false;
279
309
  try {
280
- const hidden = new Set(options.hiddenVariables);
281
310
  // Output to redact comes through Retest; any other goes straight to the log.
282
311
  const outputMode = redact === undefined && redactStream === undefined ? log.fd : 'pipe';
283
- const child = spawn(options.executable, options.args, {
284
- env: Object.fromEntries(Object.entries(process.env).filter(([name]) => !hidden.has(name))),
285
- detached: true,
286
- stdio: ['ignore', outputMode, outputMode, 'pipe', 'pipe'],
287
- });
312
+ try {
313
+ prepareOwnedLaunch();
314
+ }
315
+ catch (error) {
316
+ throw new LaunchError(`Cannot start ${options.executable}: ${errorMessage(error)}`, { cause: error });
317
+ }
318
+ let child;
319
+ try {
320
+ child = spawn(options.executable, options.args, {
321
+ env: withoutVariables(process.env, options.hiddenVariables),
322
+ detached: true,
323
+ stdio: ['ignore', outputMode, outputMode, 'pipe', 'pipe'],
324
+ });
325
+ }
326
+ catch (error) {
327
+ // Windows refuses a program whose access list denies this user running it at the spawn itself, with EPERM; the
328
+ // check before the launch cannot see that there, as it sees a mode on macOS and Linux.
329
+ const refused = errorCode(error) === 'EPERM' || errorCode(error) === 'EACCES';
330
+ throw new LaunchError(refused ? `${options.executable} is not executable. Allow it to run, or pass another browser.` : `Cannot start ${options.executable}: ${errorMessage(error)}`, { cause: error });
331
+ }
288
332
  await once(child, 'spawn').catch((error) => {
289
333
  throw new LaunchError(`Cannot start ${options.executable}: ${errorMessage(error)}`, { cause: error });
290
334
  });
291
- const ownership = new OwnedProcessGroup(child.pid ?? 0);
335
+ // Every process of the browser carries its profile's folder in its command line.
336
+ const ownership = holdLaunch(child, options.profile === undefined ? {} : { marker: basename(options.profile) });
292
337
  const ownershipProblems = ownership.capture();
293
338
  const [, , , writable, readable] = child.stdio;
294
339
  if (!(writable instanceof Writable) || !(readable instanceof Readable)) {
@@ -354,7 +399,7 @@ async function spawnInGroup(options) {
354
399
  * readers and flush accepted bytes and queued writes within that same writing bound. This does not claim remote
355
400
  * EOF or collect bytes an inherited writer sends later. An output without this support still fails and is canceled.
356
401
  */
357
- async function outputWithin(output, timeoutMs, confirmedGone) {
402
+ export async function outputWithin(output, timeoutMs, confirmedGone) {
358
403
  const first = await settledWithin(output.closed, timeoutMs);
359
404
  if (first !== undefined)
360
405
  return first;
@@ -404,7 +449,8 @@ async function openLog(logFile) {
404
449
  throw new LaunchError(`Cannot open the browser log ${logFile}: ${errorMessage(error)}`, { cause: error });
405
450
  }
406
451
  }
407
- // A fresh reading is taken before the deadline is asked, so a group that ended while the host was busy reads as ended.
452
+ // Each look reads the group, or waits for a reading already under way, before the deadline is asked, so a group that
453
+ // ended while the host was busy reads as ended.
408
454
  async function groupEnds(ownership, grace, { ref = true, deadline = grace } = {}) {
409
455
  while (await ownership.remainsAsync(deadline)) {
410
456
  if (grace.expired || deadline.reached || deadline.signal?.aborted === true)
@@ -413,21 +459,53 @@ async function groupEnds(ownership, grace, { ref = true, deadline = grace } = {}
413
459
  }
414
460
  return true;
415
461
  }
462
+ /** How long an exit hook on Windows asks again to remove a folder whose processes it confirmed gone. */
463
+ export const exitRemovalMs = 2 * closeGraceMs;
416
464
  // Runs while the Retest process exits, when a failure can neither be awaited nor reported.
417
465
  function killAtExit(ownership, profile) {
418
466
  try {
419
467
  const deadline = new Deadline(closeGraceMs);
420
468
  ownership.signalNow('SIGKILL', deadline);
421
- if (profile !== undefined && groupEndsNow(ownership, deadline))
469
+ if (profile === undefined || !groupEndsNow(ownership, deadline))
470
+ return;
471
+ // On Windows the end and its confirmation are runs of retest-supervisor, which a slow host can spend most of the
472
+ // bound on, and the folder refuses removal for up to a second after its processes left their job, as a scanner
473
+ // holds what they wrote; the removal gets a bound of its own, so a profile whose processes are confirmed gone is
474
+ // removed.
475
+ if (launchesHeldByJob)
476
+ removeOnceFree(profile, new Deadline(exitRemovalMs));
477
+ else
422
478
  rmSync(profile, { recursive: true, force: true, maxRetries: 3 });
423
479
  }
424
480
  catch {
425
481
  // Throwing here would replace the exit code Retest chose.
426
482
  }
427
483
  }
428
- // `groupEnds` for an exit hook, which cannot await. Processes just sent SIGKILL are still exiting when `ps` first reads
429
- // them, so the group is read again, a poll apart, until it is gone or the deadline passes.
430
- function groupEndsNow(ownership, deadline) {
484
+ /**
485
+ * Removes a folder from an exit hook on Windows, where a folder whose files processes just ended were using refuses
486
+ * removal for a moment after they left their job, and the synchronous removal does not wait: it is asked again, a poll
487
+ * apart, until the deadline.
488
+ */
489
+ export function removeOnceFree(folder, deadline) {
490
+ const pause = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
491
+ for (;;) {
492
+ try {
493
+ rmSync(folder, { recursive: true, force: true });
494
+ return;
495
+ }
496
+ catch (error) {
497
+ const code = errorCode(error);
498
+ if ((code !== 'EPERM' && code !== 'EBUSY' && code !== 'ENOTEMPTY') || deadline.expired)
499
+ throw error;
500
+ Atomics.wait(pause, 0, 0, Math.min(pollMs, deadline.remainingMs));
501
+ }
502
+ }
503
+ }
504
+ /**
505
+ * Whether a group is gone, for an exit hook, which cannot await. Processes just sent SIGKILL are still exiting when they
506
+ * are first read, so the group is read again, a poll apart, until it is gone or the deadline passes.
507
+ */
508
+ export function groupEndsNow(ownership, deadline) {
431
509
  const pause = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
432
510
  while (ownership.remains(deadline)) {
433
511
  if (deadline.expired)