@itmetsam/samurai-framework 0.9.0 → 0.12.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 (331) hide show
  1. package/README.md +4 -5
  2. package/dist/assert/assertion-error.d.ts +1 -1
  3. package/dist/assert/expect.d.ts +5 -50
  4. package/dist/assert/expect.js +5 -182
  5. package/dist/assert/locator-assertions.d.ts +22 -0
  6. package/dist/assert/locator-assertions.js +61 -0
  7. package/dist/assert/pending-assertions.d.ts +7 -0
  8. package/dist/assert/pending-assertions.js +40 -0
  9. package/dist/assert/text-match.d.ts +4 -0
  10. package/dist/assert/text-match.js +11 -0
  11. package/dist/assert/value-assertions.d.ts +23 -0
  12. package/dist/assert/value-assertions.js +82 -0
  13. package/dist/browser/browser-context.d.ts +0 -1
  14. package/dist/browser/browser-context.js +13 -5
  15. package/dist/browser/browser-finder.js +5 -9
  16. package/dist/browser/browser.d.ts +3 -31
  17. package/dist/browser/browser.js +36 -219
  18. package/dist/browser/chrome-launch.d.ts +14 -1
  19. package/dist/browser/chrome-launch.js +44 -1
  20. package/dist/browser/dialog-handling.d.ts +32 -0
  21. package/dist/browser/dialog-handling.js +85 -0
  22. package/dist/browser/document-watcher.d.ts +44 -0
  23. package/dist/browser/document-watcher.js +160 -0
  24. package/dist/browser/download-folders.d.ts +0 -1
  25. package/dist/browser/download-folders.js +7 -15
  26. package/dist/browser/download.js +5 -10
  27. package/dist/browser/downloads-dir.js +2 -2
  28. package/dist/browser/emit.d.ts +7 -0
  29. package/dist/browser/emit.js +16 -0
  30. package/dist/browser/emulation.d.ts +1 -1
  31. package/dist/browser/emulation.js +54 -18
  32. package/dist/browser/file-chooser.js +4 -11
  33. package/dist/browser/history.d.ts +6 -0
  34. package/dist/browser/history.js +89 -0
  35. package/dist/browser/index.d.ts +2 -0
  36. package/dist/browser/index.js +2 -0
  37. package/dist/browser/init-script.d.ts +2 -0
  38. package/dist/browser/init-script.js +16 -0
  39. package/dist/browser/launch-firefox.d.ts +20 -0
  40. package/dist/browser/launch-firefox.js +66 -0
  41. package/dist/browser/launch-flags.d.ts +18 -0
  42. package/dist/browser/launch-flags.js +100 -0
  43. package/dist/browser/lazy.d.ts +21 -0
  44. package/dist/browser/lazy.js +44 -0
  45. package/dist/browser/page-events.d.ts +44 -0
  46. package/dist/browser/page-events.js +58 -0
  47. package/dist/browser/page-logs.js +2 -9
  48. package/dist/browser/page-navigation.d.ts +58 -0
  49. package/dist/browser/page-navigation.js +108 -0
  50. package/dist/browser/page-network.d.ts +69 -0
  51. package/dist/browser/page-network.js +163 -0
  52. package/dist/browser/page-settings.d.ts +35 -0
  53. package/dist/browser/page-settings.js +51 -0
  54. package/dist/browser/page-transfers.d.ts +36 -0
  55. package/dist/browser/page-transfers.js +50 -0
  56. package/dist/browser/page.d.ts +39 -154
  57. package/dist/browser/page.js +134 -758
  58. package/dist/browser/pdf.d.ts +1 -1
  59. package/dist/browser/session.d.ts +16 -0
  60. package/dist/browser/session.js +32 -0
  61. package/dist/browser/viewport.d.ts +19 -0
  62. package/dist/browser/viewport.js +72 -0
  63. package/dist/browser/warm-up.d.ts +1 -1
  64. package/dist/browser/warm-up.js +2 -1
  65. package/dist/browsers/index.d.ts +1 -1
  66. package/dist/browsers/index.js +1 -1
  67. package/dist/browsers/pins.d.ts +0 -2
  68. package/dist/browsers/pins.js +0 -2
  69. package/dist/browsers/store.d.ts +0 -2
  70. package/dist/browsers/store.js +1 -2
  71. package/dist/cli/args.d.ts +19 -7
  72. package/dist/cli/args.js +18 -9
  73. package/dist/cli/browsers.d.ts +1 -2
  74. package/dist/cli/browsers.js +2 -2
  75. package/dist/cli/console-reporter.d.ts +4 -0
  76. package/dist/cli/console-reporter.js +15 -7
  77. package/dist/cli/flow-reporter.js +2 -1
  78. package/dist/cli/flow.d.ts +1 -2
  79. package/dist/cli/flow.js +25 -22
  80. package/dist/cli/init.js +3 -8
  81. package/dist/cli/io.d.ts +10 -0
  82. package/dist/cli/io.js +1 -0
  83. package/dist/cli/main.d.ts +3 -10
  84. package/dist/cli/main.js +11 -137
  85. package/dist/cli/paint.d.ts +2 -0
  86. package/dist/cli/paint.js +4 -0
  87. package/dist/cli/record.d.ts +4 -0
  88. package/dist/cli/record.js +93 -0
  89. package/dist/cli/usage.d.ts +1 -0
  90. package/dist/cli/usage.js +58 -0
  91. package/dist/cli/version.d.ts +2 -0
  92. package/dist/cli/version.js +7 -0
  93. package/dist/config/browsers.d.ts +11 -0
  94. package/dist/config/browsers.js +32 -0
  95. package/dist/config/config.js +8 -1
  96. package/dist/config/mask.d.ts +1 -1
  97. package/dist/config/mask.js +7 -2
  98. package/dist/config/run-settings.d.ts +1 -2
  99. package/dist/config/run-settings.js +1 -6
  100. package/dist/config/timeouts.d.ts +2 -0
  101. package/dist/config/timeouts.js +13 -0
  102. package/dist/config/workers.d.ts +14 -0
  103. package/dist/config/workers.js +29 -0
  104. package/dist/flows/run/branch-context.d.ts +14 -0
  105. package/dist/flows/run/branch-context.js +35 -0
  106. package/dist/flows/run/handlers/condition.d.ts +1 -1
  107. package/dist/flows/run/handlers/end.d.ts +1 -1
  108. package/dist/flows/run/handlers/group.d.ts +1 -1
  109. package/dist/flows/run/handlers/index.d.ts +2 -2
  110. package/dist/flows/run/handlers/parallel.d.ts +1 -1
  111. package/dist/flows/run/handlers/start.d.ts +1 -1
  112. package/dist/flows/run/handlers/support.d.ts +3 -24
  113. package/dist/flows/run/handlers/support.js +1 -1
  114. package/dist/flows/run/handlers/test.d.ts +1 -1
  115. package/dist/flows/run/handlers/types.d.ts +27 -0
  116. package/dist/flows/run/handlers/types.js +1 -0
  117. package/dist/flows/run/index.d.ts +1 -1
  118. package/dist/flows/run/prepare-flow.d.ts +14 -0
  119. package/dist/flows/run/prepare-flow.js +44 -0
  120. package/dist/flows/run/project.d.ts +33 -2
  121. package/dist/flows/run/project.js +139 -49
  122. package/dist/flows/run/run.d.ts +8 -4
  123. package/dist/flows/run/run.js +30 -194
  124. package/dist/flows/run/walker.d.ts +56 -0
  125. package/dist/flows/run/walker.js +225 -0
  126. package/dist/flows/steps/catalog.d.ts +1 -1
  127. package/dist/flows/steps/handler.d.ts +1 -1
  128. package/dist/flows/steps/set.d.ts +1 -1
  129. package/dist/index.js +1 -1
  130. package/dist/locator/actionability.d.ts +33 -0
  131. package/dist/locator/actionability.js +104 -0
  132. package/dist/locator/chain-resolver.d.ts +20 -0
  133. package/dist/locator/chain-resolver.js +102 -0
  134. package/dist/locator/document-swap.d.ts +1 -0
  135. package/dist/locator/document-swap.js +11 -0
  136. package/dist/locator/element-state.d.ts +3 -1
  137. package/dist/locator/element-state.js +11 -3
  138. package/dist/locator/file-actions.d.ts +35 -0
  139. package/dist/locator/file-actions.js +55 -0
  140. package/dist/{script/helpers.js → locator/helper-realm.js} +2 -2
  141. package/dist/locator/input-actions.d.ts +18 -0
  142. package/dist/locator/input-actions.js +80 -0
  143. package/dist/locator/label-locator.d.ts +1 -1
  144. package/dist/locator/label-locator.js +5 -12
  145. package/dist/locator/locator.d.ts +14 -37
  146. package/dist/locator/locator.js +68 -424
  147. package/dist/locator/page-scripts.d.ts +16 -0
  148. package/dist/locator/page-scripts.js +54 -0
  149. package/dist/locator/page-search.d.ts +10 -0
  150. package/dist/locator/page-search.js +19 -0
  151. package/dist/locator/selector-errors.d.ts +0 -4
  152. package/dist/locator/selector-errors.js +0 -7
  153. package/dist/locator/selector.d.ts +14 -13
  154. package/dist/locator/selector.js +10 -16
  155. package/dist/locator/text-locator.d.ts +1 -1
  156. package/dist/locator/text-locator.js +5 -9
  157. package/dist/logger/index.d.ts +6 -0
  158. package/dist/logger/index.js +14 -7
  159. package/dist/network/bidi-wire.d.ts +10 -0
  160. package/dist/network/bidi-wire.js +38 -0
  161. package/dist/network/intercept.d.ts +30 -0
  162. package/dist/network/intercept.js +130 -0
  163. package/dist/network/network-tracker.d.ts +10 -47
  164. package/dist/network/network-tracker.js +34 -68
  165. package/dist/network/network-types.d.ts +33 -0
  166. package/dist/network/network-types.js +1 -0
  167. package/dist/network/network-wait.d.ts +7 -2
  168. package/dist/network/network-wait.js +14 -4
  169. package/dist/network/response.d.ts +1 -1
  170. package/dist/network/response.js +1 -1
  171. package/dist/network/route.d.ts +92 -0
  172. package/dist/network/route.js +142 -0
  173. package/dist/network/router.d.ts +6 -91
  174. package/dist/network/router.js +25 -258
  175. package/dist/recorder/expectation.d.ts +5 -0
  176. package/dist/recorder/expectation.js +20 -0
  177. package/dist/recorder/files-recorder.d.ts +30 -0
  178. package/dist/recorder/files-recorder.js +88 -0
  179. package/dist/recorder/normalise.d.ts +17 -6
  180. package/dist/recorder/normalise.js +96 -91
  181. package/dist/recorder/options.d.ts +56 -0
  182. package/dist/recorder/options.js +1 -0
  183. package/dist/recorder/page-messages.d.ts +35 -0
  184. package/dist/recorder/page-messages.js +26 -0
  185. package/dist/recorder/ranking.js +1 -0
  186. package/dist/recorder/realms.d.ts +6 -0
  187. package/dist/recorder/realms.js +13 -0
  188. package/dist/recorder/recorder.d.ts +10 -74
  189. package/dist/recorder/recorder.js +39 -199
  190. package/dist/recorder/session-browser.d.ts +22 -0
  191. package/dist/recorder/session-browser.js +21 -0
  192. package/dist/recorder/session-secrets.d.ts +8 -0
  193. package/dist/recorder/session-secrets.js +45 -0
  194. package/dist/recorder/session.d.ts +7 -13
  195. package/dist/recorder/session.js +22 -117
  196. package/dist/recorder/spec-source.d.ts +39 -0
  197. package/dist/recorder/spec-source.js +84 -0
  198. package/dist/recorder/toolbar/action-guard.d.ts +21 -0
  199. package/dist/recorder/toolbar/action-guard.js +43 -0
  200. package/dist/recorder/toolbar/actions/assert.d.ts +4 -0
  201. package/dist/recorder/toolbar/actions/assert.js +52 -0
  202. package/dist/recorder/toolbar/actions/insert.d.ts +6 -0
  203. package/dist/recorder/toolbar/actions/insert.js +93 -0
  204. package/dist/recorder/toolbar/actions/pick.d.ts +8 -0
  205. package/dist/recorder/toolbar/actions/pick.js +26 -0
  206. package/dist/recorder/toolbar/actions/reply.d.ts +7 -0
  207. package/dist/recorder/toolbar/actions/reply.js +10 -0
  208. package/dist/recorder/toolbar/controller-fixture.d.ts +47 -0
  209. package/dist/recorder/toolbar/controller-fixture.js +129 -0
  210. package/dist/recorder/toolbar/controller.d.ts +12 -78
  211. package/dist/recorder/toolbar/controller.js +35 -247
  212. package/dist/recorder/toolbar/inspect.d.ts +1 -3
  213. package/dist/recorder/toolbar/inspect.js +2 -2
  214. package/dist/recorder/toolbar/page-scope.d.ts +19 -0
  215. package/dist/recorder/toolbar/page-scope.js +43 -0
  216. package/dist/recorder/toolbar/protocol.d.ts +2 -1
  217. package/dist/recorder/toolbar/source/attach.d.ts +2 -0
  218. package/dist/recorder/toolbar/source/attach.js +41 -0
  219. package/dist/recorder/toolbar/source/dom.d.ts +2 -0
  220. package/dist/recorder/toolbar/source/dom.js +47 -0
  221. package/dist/recorder/toolbar/source/drag.d.ts +2 -0
  222. package/dist/recorder/toolbar/source/drag.js +32 -0
  223. package/dist/recorder/toolbar/source/events-page.d.ts +2 -0
  224. package/dist/recorder/toolbar/source/events-page.js +67 -0
  225. package/dist/recorder/toolbar/source/events-toolbar.d.ts +2 -0
  226. package/dist/recorder/toolbar/source/events-toolbar.js +35 -0
  227. package/dist/recorder/toolbar/source/fields.d.ts +2 -0
  228. package/dist/recorder/toolbar/source/fields.js +44 -0
  229. package/dist/recorder/toolbar/source/handlers.d.ts +2 -0
  230. package/dist/recorder/toolbar/source/handlers.js +134 -0
  231. package/dist/recorder/toolbar/source/names.d.ts +2 -0
  232. package/dist/recorder/toolbar/source/names.js +12 -0
  233. package/dist/recorder/toolbar/source/picking.d.ts +2 -0
  234. package/dist/recorder/toolbar/source/picking.js +72 -0
  235. package/dist/recorder/toolbar/source/placement.d.ts +2 -0
  236. package/dist/recorder/toolbar/source/placement.js +45 -0
  237. package/dist/recorder/toolbar/source/recorder-side.d.ts +2 -0
  238. package/dist/recorder/toolbar/source/recorder-side.js +54 -0
  239. package/dist/recorder/toolbar/source/setup.d.ts +2 -0
  240. package/dist/recorder/toolbar/source/setup.js +50 -0
  241. package/dist/recorder/toolbar/source/views-panels.d.ts +2 -0
  242. package/dist/recorder/toolbar/source/views-panels.js +150 -0
  243. package/dist/recorder/toolbar/source/views-rail.d.ts +2 -0
  244. package/dist/recorder/toolbar/source/views-rail.js +40 -0
  245. package/dist/recorder/toolbar/source/views-render.d.ts +2 -0
  246. package/dist/recorder/toolbar/source/views-render.js +48 -0
  247. package/dist/recorder/toolbar/source.js +30 -856
  248. package/dist/recorder/toolbar/types.d.ts +70 -0
  249. package/dist/recorder/toolbar/types.js +1 -0
  250. package/dist/recorder/toolbar-bridge.d.ts +43 -0
  251. package/dist/recorder/toolbar-bridge.js +106 -0
  252. package/dist/runner/browsers.d.ts +10 -0
  253. package/dist/runner/browsers.js +12 -0
  254. package/dist/runner/groups.d.ts +5 -1
  255. package/dist/runner/groups.js +9 -2
  256. package/dist/runner/options.d.ts +31 -0
  257. package/dist/runner/options.js +1 -0
  258. package/dist/runner/pooled-run.d.ts +43 -0
  259. package/dist/runner/pooled-run.js +75 -0
  260. package/dist/runner/ports.d.ts +2 -0
  261. package/dist/runner/ports.js +2 -0
  262. package/dist/runner/registry.d.ts +1 -1
  263. package/dist/runner/registry.js +1 -1
  264. package/dist/runner/reporter.d.ts +40 -11
  265. package/dist/runner/reporter.js +69 -16
  266. package/dist/runner/run-test.d.ts +16 -0
  267. package/dist/runner/run-test.js +178 -0
  268. package/dist/runner/run.d.ts +5 -2
  269. package/dist/runner/run.js +28 -28
  270. package/dist/runner/select.d.ts +24 -0
  271. package/dist/runner/select.js +77 -0
  272. package/dist/runner/test-dir.d.ts +13 -0
  273. package/dist/runner/test-dir.js +27 -0
  274. package/dist/runner/test-runner.d.ts +27 -50
  275. package/dist/runner/test-runner.js +102 -264
  276. package/dist/runner/worker-pool.d.ts +67 -0
  277. package/dist/runner/worker-pool.js +275 -0
  278. package/dist/runner/worker-process.d.ts +6 -0
  279. package/dist/runner/worker-process.js +54 -0
  280. package/dist/runner/worker-protocol.d.ts +67 -0
  281. package/dist/runner/worker-protocol.js +1 -0
  282. package/dist/runner/worker-session.d.ts +7 -0
  283. package/dist/runner/worker-session.js +60 -0
  284. package/dist/runner/worker.d.ts +26 -0
  285. package/dist/runner/worker.js +121 -0
  286. package/dist/runner/workers-option.d.ts +15 -0
  287. package/dist/runner/workers-option.js +22 -0
  288. package/dist/script/call-function.d.ts +1 -9
  289. package/dist/script/call-function.js +2 -19
  290. package/dist/script/element-handle.d.ts +1 -2
  291. package/dist/script/element-handle.js +1 -2
  292. package/dist/script/serialize.d.ts +3 -12
  293. package/dist/script/serialize.js +53 -62
  294. package/dist/steps/parse/call.d.ts +3 -0
  295. package/dist/steps/parse/call.js +81 -0
  296. package/dist/steps/parse/expectation.d.ts +5 -0
  297. package/dist/steps/parse/expectation.js +71 -0
  298. package/dist/steps/parse/file-entry.d.ts +4 -0
  299. package/dist/steps/parse/file-entry.js +74 -0
  300. package/dist/steps/parse/literals.d.ts +4 -0
  301. package/dist/steps/parse/literals.js +28 -0
  302. package/dist/steps/parse/step.d.ts +4 -0
  303. package/dist/steps/parse/step.js +81 -0
  304. package/dist/steps/parse.js +2 -323
  305. package/dist/transport/bidi-connection.d.ts +4 -2
  306. package/dist/transport/bidi-connection.js +9 -43
  307. package/dist/transport/log-redaction.d.ts +13 -0
  308. package/dist/transport/log-redaction.js +51 -0
  309. package/dist/transport/subscriptions.js +18 -13
  310. package/dist/transport/unsupported.d.ts +7 -0
  311. package/dist/transport/unsupported.js +13 -0
  312. package/dist/types/bidi-modules/browser.d.ts +1 -12
  313. package/dist/types/bidi-modules/browsing-context.d.ts +8 -18
  314. package/dist/types/bidi-modules/emulation.d.ts +29 -21
  315. package/dist/types/bidi-modules/input.d.ts +1 -9
  316. package/dist/types/bidi-modules/network.d.ts +29 -24
  317. package/dist/types/bidi-modules/script.d.ts +0 -9
  318. package/dist/types/bidi-modules/session.d.ts +0 -8
  319. package/dist/types/bidi-modules/storage.d.ts +0 -5
  320. package/dist/types/bidi.d.ts +7 -37
  321. package/dist/types/config.d.ts +17 -3
  322. package/dist/types/test.d.ts +15 -2
  323. package/dist/wait/wait-until.d.ts +1 -5
  324. package/dist/wait/wait-until.js +7 -16
  325. package/package.json +3 -2
  326. package/dist/config/default.d.ts +0 -2
  327. package/dist/config/default.js +0 -3
  328. package/dist/types/bidi-modules/web-extensions.d.ts +0 -9
  329. package/dist/types/bidi-protocols/command.d.ts +0 -7
  330. package/dist/types/bidi-protocols/event.d.ts +0 -17
  331. /package/dist/{script/helpers.d.ts → locator/helper-realm.d.ts} +0 -0
@@ -0,0 +1,54 @@
1
+ /** Page-side source strings and the actionability checks each action waits for */
2
+ /** What `setInputFiles` needs to know about the element before it sends files */
3
+ export const FILE_INPUT_INFO = `(el) => ({
4
+ tag: el.tagName.toLowerCase(),
5
+ type: (el.getAttribute("type") || "").toLowerCase(),
6
+ multiple: Boolean(el.multiple),
7
+ })`;
8
+ export const FILE_INPUT_CHECKS = ["attached", "enabled"];
9
+ export const DROP_CHECKS = ["attached", "visible"];
10
+ /** The sandbox `dropFiles` builds its files in */
11
+ export const DROP_SANDBOX = "samurai-drop";
12
+ const DROP_KEY = `globalThis[Symbol.for("samurai.drop")]`;
13
+ export const DROP_INPUT = `() => {
14
+ const input = document.createElement("input");
15
+ input.type = "file";
16
+ input.multiple = true;
17
+ ${DROP_KEY} = input;
18
+ return input;
19
+ }`;
20
+ /** Fires dragenter, dragover and drop at the element's centre with the input's files (retyped where asked) */
21
+ export const DROP_EVENTS = `(el, types) => {
22
+ const input = ${DROP_KEY};
23
+ delete ${DROP_KEY};
24
+ const data = new DataTransfer();
25
+ Array.from(input.files).forEach((file, i) => {
26
+ data.items.add(types[i] ? new File([file], file.name, { type: types[i], lastModified: file.lastModified }) : file);
27
+ });
28
+ const box = el.getBoundingClientRect();
29
+ const at = { clientX: box.left + box.width / 2, clientY: box.top + box.height / 2 };
30
+ for (const type of ["dragenter", "dragover", "drop"]) {
31
+ el.dispatchEvent(new DragEvent(type, Object.assign({ bubbles: true, cancelable: true, composed: true, dataTransfer: data }, at)));
32
+ }
33
+ }`;
34
+ export const SCREENSHOT_CHECKS = ["attached", "visible"];
35
+ export const CLICK_CHECKS = [
36
+ "attached",
37
+ "visible",
38
+ "stable",
39
+ "enabled",
40
+ "hit target",
41
+ ];
42
+ export const FILL_CHECKS = [
43
+ "attached",
44
+ "visible",
45
+ "enabled",
46
+ "editable",
47
+ "hit target",
48
+ ];
49
+ export const PRESS_CHECKS = [
50
+ "attached",
51
+ "visible",
52
+ "enabled",
53
+ ];
54
+ export const ATTACHED_ONLY = ["attached"];
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Page-side pieces the text and label searches share. They are strings, glued into the function declarations
3
+ * of `TEXT_LOCATE` and `LABEL_LOCATE`, which run in the page with `(starts, value, match, ignoreCase)` in scope.
4
+ */
5
+ /** `normalise` collapses whitespace and trims (lower-casing with `ignoreCase`); `textMatches` compares a text with `value` by `match` */
6
+ export declare const MATCHING_JS = "\n const normalise = (text) => {\n const collapsed = String(text).replace(/\\s+/g, \" \").trim();\n return ignoreCase ? collapsed.toLowerCase() : collapsed;\n };\n const wanted = normalise(value);\n const textMatches = (text) => {\n const normal = normalise(text);\n return match === \"full\" ? normal === wanted : normal.includes(wanted);\n };";
7
+ /** The nodes to search in: the start nodes, else the whole document */
8
+ export declare const ROOTS_JS = "const roots = starts.length > 0 ? starts : [document];";
9
+ /** A sort callback putting elements in document order */
10
+ export declare const DOCUMENT_ORDER_JS = "(a, b) => (a === b ? 0 : a.compareDocumentPosition(b) & 4 ? -1 : 1)";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Page-side pieces the text and label searches share. They are strings, glued into the function declarations
3
+ * of `TEXT_LOCATE` and `LABEL_LOCATE`, which run in the page with `(starts, value, match, ignoreCase)` in scope.
4
+ */
5
+ /** `normalise` collapses whitespace and trims (lower-casing with `ignoreCase`); `textMatches` compares a text with `value` by `match` */
6
+ export const MATCHING_JS = `
7
+ const normalise = (text) => {
8
+ const collapsed = String(text).replace(/\\s+/g, " ").trim();
9
+ return ignoreCase ? collapsed.toLowerCase() : collapsed;
10
+ };
11
+ const wanted = normalise(value);
12
+ const textMatches = (text) => {
13
+ const normal = normalise(text);
14
+ return match === "full" ? normal === wanted : normal.includes(wanted);
15
+ };`;
16
+ /** The nodes to search in: the start nodes, else the whole document */
17
+ export const ROOTS_JS = `const roots = starts.length > 0 ? starts : [document];`;
18
+ /** A sort callback putting elements in document order */
19
+ export const DOCUMENT_ORDER_JS = `(a, b) => (a === b ? 0 : a.compareDocumentPosition(b) & 4 ? -1 : 1)`;
@@ -3,7 +3,3 @@ export declare class InvalidSelectorError extends Error {
3
3
  readonly selector: string;
4
4
  constructor(selector: string, reason: string);
5
5
  }
6
- /** The browser does not implement this kind of locator */
7
- export declare class UnsupportedOperationError extends Error {
8
- constructor(message: string);
9
- }
@@ -6,10 +6,3 @@ export class InvalidSelectorError extends Error {
6
6
  this.selector = selector;
7
7
  }
8
8
  }
9
- /** The browser does not implement this kind of locator */
10
- export class UnsupportedOperationError extends Error {
11
- constructor(message) {
12
- super(message);
13
- this.name = "UnsupportedOperationError";
14
- }
15
- }
@@ -6,23 +6,17 @@ export type Selector = {
6
6
  } | {
7
7
  kind: "css";
8
8
  value: string;
9
- } | {
9
+ } | ({
10
10
  kind: "text";
11
- value: string;
12
- match: "full" | "partial";
13
- ignoreCase: boolean;
14
- } | {
11
+ } & TextMatch) | {
15
12
  kind: "role";
16
- role?: string;
13
+ role: string;
17
14
  name?: string;
18
15
  }
19
16
  /** Form controls named by a `<label>`, `aria-labelledby` or `aria-label` whose text matches */
20
- | {
17
+ | ({
21
18
  kind: "label";
22
- value: string;
23
- match: "full" | "partial";
24
- ignoreCase: boolean;
25
- }
19
+ } & TextMatch)
26
20
  /** Elements whose `data-testid` attribute equals `value` */
27
21
  | {
28
22
  kind: "testid";
@@ -33,6 +27,12 @@ export type Selector = {
33
27
  kind: "nth";
34
28
  index: number;
35
29
  };
30
+ /** What a text or label step looks for */
31
+ interface TextMatch {
32
+ value: string;
33
+ match: "full" | "partial";
34
+ ignoreCase: boolean;
35
+ }
36
36
  export interface TextOptions {
37
37
  /** @default "full" */
38
38
  match?: "full" | "partial";
@@ -41,8 +41,8 @@ export interface TextOptions {
41
41
  }
42
42
  export declare function xpathSelector(value: string): Selector;
43
43
  export declare function cssSelector(value: string): Selector;
44
- export declare function textSelector(value: string, { match, ignoreCase }?: TextOptions): Selector;
45
- export declare function labelSelector(value: string, { match, ignoreCase }?: TextOptions): Selector;
44
+ export declare function textSelector(value: string, options?: TextOptions): Selector;
45
+ export declare function labelSelector(value: string, options?: TextOptions): Selector;
46
46
  export declare function testIdSelector(value: string): Selector;
47
47
  export declare function roleSelector(role: string, { name }?: {
48
48
  name?: string;
@@ -58,3 +58,4 @@ export declare function toBiDiLocator(selector: Selector, scoped: boolean): Node
58
58
  /** A short name for error messages */
59
59
  export declare function describeSelector(selector: Selector, scoped: boolean): string;
60
60
  export declare function describeChain(chain: readonly Selector[]): string;
61
+ export {};
@@ -9,21 +9,14 @@ export function xpathSelector(value) {
9
9
  export function cssSelector(value) {
10
10
  return { kind: "css", value: nonEmpty(value, "a css selector") };
11
11
  }
12
- export function textSelector(value, { match = "full", ignoreCase = false } = {}) {
13
- return {
14
- kind: "text",
15
- value: nonEmpty(value, "the text"),
16
- match,
17
- ignoreCase,
18
- };
12
+ function textMatch(value, what, { match = "full", ignoreCase = false }) {
13
+ return { value: nonEmpty(value, what), match, ignoreCase };
19
14
  }
20
- export function labelSelector(value, { match = "full", ignoreCase = false } = {}) {
21
- return {
22
- kind: "label",
23
- value: nonEmpty(value, "the label"),
24
- match,
25
- ignoreCase,
26
- };
15
+ export function textSelector(value, options = {}) {
16
+ return { kind: "text", ...textMatch(value, "the text", options) };
17
+ }
18
+ export function labelSelector(value, options = {}) {
19
+ return { kind: "label", ...textMatch(value, "the label", options) };
27
20
  }
28
21
  export function testIdSelector(value) {
29
22
  return { kind: "testid", value: nonEmpty(value, "the test id") };
@@ -65,7 +58,7 @@ export function toBiDiLocator(selector, scoped) {
65
58
  return {
66
59
  type: "accessibility",
67
60
  value: {
68
- ...(selector.role !== undefined && { role: selector.role }),
61
+ role: selector.role,
69
62
  ...(selector.name !== undefined && { name: selector.name }),
70
63
  },
71
64
  };
@@ -74,6 +67,7 @@ export function toBiDiLocator(selector, scoped) {
74
67
  type: "css",
75
68
  value: `[data-testid="${selector.value.replace(/["\\]/g, "\\$&")}"]`,
76
69
  };
70
+ // The locator resolves these two itself, so a chain never hands them to the browser
77
71
  case "label":
78
72
  throw new Error("label is resolved by the framework, not by the browser");
79
73
  case "nth":
@@ -98,7 +92,7 @@ export function describeSelector(selector, scoped) {
98
92
  case "testid":
99
93
  return `testid=${JSON.stringify(selector.value)}`;
100
94
  case "role":
101
- return (`role=${selector.role ?? ""}` +
95
+ return (`role=${selector.role}` +
102
96
  (selector.name === undefined
103
97
  ? ""
104
98
  : `[name=${JSON.stringify(selector.name)}]`));
@@ -10,4 +10,4 @@
10
10
  *
11
11
  * A string, so the transpiler cannot inject helpers that do not exist in the page.
12
12
  */
13
- export declare const TEXT_LOCATE = "(starts, value, match, ignoreCase) => {\n const skipped = new Set([\"SCRIPT\", \"STYLE\", \"NOSCRIPT\", \"TEMPLATE\", \"HEAD\", \"TITLE\", \"META\", \"LINK\"]);\n const normalise = (text) => {\n const collapsed = String(text).replace(/\\s+/g, \" \").trim();\n return ignoreCase ? collapsed.toLowerCase() : collapsed;\n };\n const wanted = normalise(value);\n const roots = starts.length > 0 ? starts : [document];\n const seen = new Set();\n const matches = [];\n for (const root of roots) {\n for (const el of root.querySelectorAll(\"*\")) {\n if (seen.has(el) || skipped.has(el.tagName.toUpperCase())) continue;\n seen.add(el);\n const text = normalise(el.innerText ?? el.textContent ?? \"\");\n if (match === \"full\" ? text === wanted : text.includes(wanted)) matches.push(el);\n }\n }\n const hasMatchingDescendant = new Set();\n for (const el of matches) {\n for (let parent = el.parentElement; parent; parent = parent.parentElement) hasMatchingDescendant.add(parent);\n }\n return matches\n .filter((el) => !hasMatchingDescendant.has(el))\n .sort((a, b) => (a.compareDocumentPosition(b) & 4 ? -1 : 1));\n}";
13
+ export declare const TEXT_LOCATE = "(starts, value, match, ignoreCase) => {\n const skipped = new Set([\"SCRIPT\", \"STYLE\", \"NOSCRIPT\", \"TEMPLATE\", \"HEAD\", \"TITLE\", \"META\", \"LINK\"]);\n \n const normalise = (text) => {\n const collapsed = String(text).replace(/\\s+/g, \" \").trim();\n return ignoreCase ? collapsed.toLowerCase() : collapsed;\n };\n const wanted = normalise(value);\n const textMatches = (text) => {\n const normal = normalise(text);\n return match === \"full\" ? normal === wanted : normal.includes(wanted);\n };\n const roots = starts.length > 0 ? starts : [document];\n const seen = new Set();\n const matches = [];\n for (const root of roots) {\n for (const el of root.querySelectorAll(\"*\")) {\n if (seen.has(el) || skipped.has(el.tagName.toUpperCase())) continue;\n seen.add(el);\n if (textMatches(el.innerText ?? el.textContent ?? \"\")) matches.push(el);\n }\n }\n const hasMatchingDescendant = new Set();\n for (const el of matches) {\n for (let parent = el.parentElement; parent; parent = parent.parentElement) hasMatchingDescendant.add(parent);\n }\n return matches\n .filter((el) => !hasMatchingDescendant.has(el))\n .sort((a, b) => (a === b ? 0 : a.compareDocumentPosition(b) & 4 ? -1 : 1));\n}";
@@ -1,3 +1,4 @@
1
+ import { DOCUMENT_ORDER_JS, MATCHING_JS, ROOTS_JS } from "./page-search.js";
1
2
  /**
2
3
  * Function declaration run in the page as `(starts, value, match, ignoreCase)`; returns the elements
3
4
  * whose text matches. Used when the browser does not implement BiDi's `innerText` locator
@@ -12,20 +13,15 @@
12
13
  */
13
14
  export const TEXT_LOCATE = `(starts, value, match, ignoreCase) => {
14
15
  const skipped = new Set(["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE", "HEAD", "TITLE", "META", "LINK"]);
15
- const normalise = (text) => {
16
- const collapsed = String(text).replace(/\\s+/g, " ").trim();
17
- return ignoreCase ? collapsed.toLowerCase() : collapsed;
18
- };
19
- const wanted = normalise(value);
20
- const roots = starts.length > 0 ? starts : [document];
16
+ ${MATCHING_JS}
17
+ ${ROOTS_JS}
21
18
  const seen = new Set();
22
19
  const matches = [];
23
20
  for (const root of roots) {
24
21
  for (const el of root.querySelectorAll("*")) {
25
22
  if (seen.has(el) || skipped.has(el.tagName.toUpperCase())) continue;
26
23
  seen.add(el);
27
- const text = normalise(el.innerText ?? el.textContent ?? "");
28
- if (match === "full" ? text === wanted : text.includes(wanted)) matches.push(el);
24
+ if (textMatches(el.innerText ?? el.textContent ?? "")) matches.push(el);
29
25
  }
30
26
  }
31
27
  const hasMatchingDescendant = new Set();
@@ -34,5 +30,5 @@ export const TEXT_LOCATE = `(starts, value, match, ignoreCase) => {
34
30
  }
35
31
  return matches
36
32
  .filter((el) => !hasMatchingDescendant.has(el))
37
- .sort((a, b) => (a.compareDocumentPosition(b) & 4 ? -1 : 1));
33
+ .sort(${DOCUMENT_ORDER_JS});
38
34
  }`;
@@ -1,2 +1,8 @@
1
+ /** One console line: `LEVEL: message`, then the line's own metadata as JSON when it has any */
2
+ export declare function consoleLine(entry: {
3
+ level: string;
4
+ message: unknown;
5
+ meta?: Record<string, unknown> | undefined;
6
+ }): string;
1
7
  declare const logger: import("winston").Logger;
2
8
  export default logger;
@@ -1,5 +1,13 @@
1
1
  import { createLogger, format, transports } from "winston";
2
2
  import { maskFormat } from "../config/mask.js";
3
+ /** Metadata every line carries (`defaultMeta`): not worth printing on each console line */
4
+ const DEFAULT_META_KEYS = ["service"];
5
+ /** One console line: `LEVEL: message`, then the line's own metadata as JSON when it has any */
6
+ export function consoleLine(entry) {
7
+ const own = Object.fromEntries(Object.entries(entry.meta ?? {}).filter(([key]) => !DEFAULT_META_KEYS.includes(key)));
8
+ const meta = Object.keys(own).length > 0 ? `\n${JSON.stringify(own)}` : "";
9
+ return `${entry.level.toUpperCase()}: ${String(entry.message)}${meta}`;
10
+ }
3
11
  const logger = createLogger({
4
12
  level: "debug",
5
13
  format: format.combine(format.timestamp({
@@ -7,18 +15,17 @@ const logger = createLogger({
7
15
  }), format.errors({ stack: true }), format.splat(), format.metadata({ key: "meta" }), maskFormat(), format.json({ space: 2 })),
8
16
  defaultMeta: { service: "samurai-framework" },
9
17
  transports: [
10
- //
11
- // - Write to all logs with level `info` and below to `quick-start-combined.log`.
12
- // - Write all logs error (and below) to `quick-start-error.log`.
13
- //
18
+ // The console shows the log; `logs/error.log` keeps errors and `logs/combined.log` everything
14
19
  new transports.Console({
15
20
  // The `samurai` command quiets this to "warn"; the log files keep everything
16
21
  level: process.env.SAMURAI_LOG_LEVEL ?? "debug",
17
22
  // stdout stays free for a command's own output (`samurai run --json`)
18
23
  stderrLevels: ["error", "warn", "info", "verbose", "debug"],
19
- format: format.combine(format.timestamp(), format.errors({ stack: true }), format.printf(({ level, message, meta }) => {
20
- return `${level.toUpperCase()}: ${message}${meta ? `\n${JSON.stringify(meta)}` : null}`;
21
- })),
24
+ format: format.combine(format.timestamp(), format.errors({ stack: true }), format.printf(({ level, message, meta }) => consoleLine({
25
+ level,
26
+ message,
27
+ meta: meta,
28
+ }))),
22
29
  }),
23
30
  new transports.File({
24
31
  filename: `logs/error.log`,
@@ -0,0 +1,10 @@
1
+ import type { BytesValue, Header, RequestData } from "../types/bidi-modules/network.js";
2
+ import type { NetworkRequest } from "./network-types.js";
3
+ /** Header list to a lower-cased record; repeated names are joined, base64 values decoded */
4
+ export declare function headersFromBidi(headers: Header[]): Record<string, string>;
5
+ /** A record of headers as the list BiDi commands take */
6
+ export declare function headersToBidi(headers: Record<string, string>): Header[];
7
+ /** A body as BiDi takes it: text as is, bytes as base64 */
8
+ export declare function toBytes(data: string | Buffer): BytesValue;
9
+ /** The request a `network.*` event describes */
10
+ export declare function toRequest(data: RequestData, navigation: string | null, isBlocked: boolean, redirectedFrom: NetworkRequest | null): NetworkRequest;
@@ -0,0 +1,38 @@
1
+ /** Header list to a lower-cased record; repeated names are joined, base64 values decoded */
2
+ export function headersFromBidi(headers) {
3
+ const result = {};
4
+ for (const { name, value } of headers) {
5
+ const text = value.type === "base64"
6
+ ? Buffer.from(value.value, "base64").toString("utf8")
7
+ : value.value;
8
+ const key = name.toLowerCase();
9
+ result[key] = key in result ? `${result[key]}, ${text}` : text;
10
+ }
11
+ return result;
12
+ }
13
+ /** A record of headers as the list BiDi commands take */
14
+ export function headersToBidi(headers) {
15
+ return Object.entries(headers).map(([name, value]) => ({
16
+ name,
17
+ value: { type: "string", value },
18
+ }));
19
+ }
20
+ /** A body as BiDi takes it: text as is, bytes as base64 */
21
+ export function toBytes(data) {
22
+ return typeof data === "string"
23
+ ? { type: "string", value: data }
24
+ : { type: "base64", value: data.toString("base64") };
25
+ }
26
+ /** The request a `network.*` event describes */
27
+ export function toRequest(data, navigation, isBlocked, redirectedFrom) {
28
+ return {
29
+ id: data.request,
30
+ url: data.url,
31
+ method: data.method,
32
+ headers: headersFromBidi(data.headers),
33
+ resourceType: data.destination || data.initiatorType || "other",
34
+ navigation,
35
+ redirectedFrom,
36
+ isBlocked,
37
+ };
38
+ }
@@ -0,0 +1,30 @@
1
+ import type { BiDiConnector } from "../transport/bidi-connection.js";
2
+ import type { BeforeRequestSentParameters } from "../types/bidi-modules/network.js";
3
+ import { type UrlPattern } from "./url-match.js";
4
+ /**
5
+ * Keeps one browser-side `network.addIntercept` equal to a page's routes: none, one for everything, or one for
6
+ * the exact URLs the routes name. Changes are queued, so two `sync` calls never overlap. Requests the intercept
7
+ * holds are handed to `onBlocked`.
8
+ */
9
+ export declare class Intercept {
10
+ private connector;
11
+ private contextId;
12
+ private onBlocked;
13
+ private queue;
14
+ private ids;
15
+ private currentKey;
16
+ private currentId;
17
+ private subscription;
18
+ constructor(connector: BiDiConnector, contextId: string, onBlocked: (params: BeforeRequestSentParameters) => void);
19
+ /** Whether one of `intercepts` is ours: a request held by someone else's intercept is not for us */
20
+ holds(intercepts: readonly string[] | undefined): boolean;
21
+ /** Makes the browser-side intercept match the routes' patterns, after the changes queued before this one */
22
+ sync(patterns: readonly UrlPattern[]): Promise<void>;
23
+ private apply;
24
+ /** The exact URLs to block, or undefined to block everything and match in the router */
25
+ private urlPatterns;
26
+ private addIntercept;
27
+ private removeIntercept;
28
+ private listen;
29
+ private stop;
30
+ }
@@ -0,0 +1,130 @@
1
+ import { BiDiError } from "../transport/bidi-error.js";
2
+ import { isExactString } from "./url-match.js";
3
+ /** Whether a browser accepts `urlPatterns` in `network.addIntercept`; asked once per connection */
4
+ const patternsUnsupported = new WeakSet();
5
+ /**
6
+ * Keeps one browser-side `network.addIntercept` equal to a page's routes: none, one for everything, or one for
7
+ * the exact URLs the routes name. Changes are queued, so two `sync` calls never overlap. Requests the intercept
8
+ * holds are handed to `onBlocked`.
9
+ */
10
+ export class Intercept {
11
+ constructor(connector, contextId, onBlocked) {
12
+ this.connector = connector;
13
+ this.contextId = contextId;
14
+ this.onBlocked = onBlocked;
15
+ this.queue = Promise.resolve();
16
+ this.ids = new Set();
17
+ }
18
+ /** Whether one of `intercepts` is ours: a request held by someone else's intercept is not for us */
19
+ holds(intercepts) {
20
+ return (intercepts ?? []).some((id) => this.ids.has(id));
21
+ }
22
+ /** Makes the browser-side intercept match the routes' patterns, after the changes queued before this one */
23
+ sync(patterns) {
24
+ const run = this.queue.then(() => this.apply(patterns));
25
+ this.queue = run.catch(() => undefined);
26
+ return run;
27
+ }
28
+ async apply(routePatterns) {
29
+ if (routePatterns.length === 0)
30
+ return this.stop();
31
+ await this.listen();
32
+ const patterns = this.urlPatterns(routePatterns);
33
+ const key = patterns ? JSON.stringify(patterns) : "all";
34
+ if (key === this.currentKey)
35
+ return;
36
+ const id = await this.addIntercept(patterns);
37
+ const previous = this.currentId;
38
+ this.currentId = id;
39
+ this.currentKey =
40
+ patterns && !patternsUnsupported.has(this.connector) ? key : "all";
41
+ this.ids.add(id);
42
+ // The new intercept is in place before the old one goes: nothing slips through in between
43
+ if (previous !== undefined)
44
+ await this.removeIntercept(previous);
45
+ }
46
+ /** The exact URLs to block, or undefined to block everything and match in the router */
47
+ urlPatterns(routePatterns) {
48
+ if (patternsUnsupported.has(this.connector))
49
+ return undefined;
50
+ const patterns = [];
51
+ for (const pattern of routePatterns) {
52
+ // The browser reads a URL string in normal form; anything else could mean something else to it
53
+ if (!isExactString(pattern) || !isNormalUrl(pattern))
54
+ return undefined;
55
+ if (!patterns.some((existing) => existing.type === "string" && existing.pattern === pattern)) {
56
+ patterns.push({ type: "string", pattern });
57
+ }
58
+ }
59
+ return patterns;
60
+ }
61
+ async addIntercept(patterns) {
62
+ const params = {
63
+ phases: ["beforeRequestSent"],
64
+ contexts: [this.contextId],
65
+ };
66
+ try {
67
+ const { intercept } = await this.connector.send("network.addIntercept", {
68
+ ...params,
69
+ ...(patterns && { urlPatterns: patterns }),
70
+ });
71
+ return intercept;
72
+ }
73
+ catch (err) {
74
+ if (patterns &&
75
+ err instanceof BiDiError &&
76
+ err.code === "invalid argument") {
77
+ patternsUnsupported.add(this.connector);
78
+ return this.addIntercept(undefined);
79
+ }
80
+ throw err;
81
+ }
82
+ }
83
+ async removeIntercept(id) {
84
+ try {
85
+ await this.connector.send("network.removeIntercept", { intercept: id });
86
+ }
87
+ catch (err) {
88
+ if (!(err instanceof BiDiError && err.code === "no such intercept"))
89
+ throw err;
90
+ }
91
+ finally {
92
+ this.ids.delete(id);
93
+ }
94
+ }
95
+ async listen() {
96
+ if (this.subscription)
97
+ return;
98
+ this.connector.onEvent("network.beforeRequestSent", this.onBlocked);
99
+ try {
100
+ this.subscription = await this.connector.subscribe([
101
+ "network.beforeRequestSent",
102
+ ]);
103
+ }
104
+ catch (err) {
105
+ this.connector.offEvent("network.beforeRequestSent", this.onBlocked);
106
+ throw err;
107
+ }
108
+ }
109
+ async stop() {
110
+ const id = this.currentId;
111
+ this.currentId = undefined;
112
+ this.currentKey = undefined;
113
+ if (id !== undefined)
114
+ await this.removeIntercept(id);
115
+ if (this.subscription) {
116
+ this.connector.offEvent("network.beforeRequestSent", this.onBlocked);
117
+ const subscription = this.subscription;
118
+ this.subscription = undefined;
119
+ await subscription.unsubscribe();
120
+ }
121
+ }
122
+ }
123
+ function isNormalUrl(value) {
124
+ try {
125
+ return new URL(value).href === value;
126
+ }
127
+ catch {
128
+ return false;
129
+ }
130
+ }
@@ -1,47 +1,12 @@
1
1
  import type { ContextTree } from "../browser/context-tree.js";
2
2
  import type { BiDiConnector } from "../transport/bidi-connection.js";
3
- import type { Header, RequestData } from "../types/bidi-modules/network.js";
4
- import { WaitTimeoutError } from "../wait/wait-until.js";
5
- export interface NetworkRequest {
6
- /** The browser's id; the same for every hop of a redirect chain */
7
- id: string;
8
- url: string;
9
- method: string;
10
- /** Header names lower-cased; repeated headers joined with ", " */
11
- headers: Record<string, string>;
12
- /** "document", "script", "image", …; falls back to the initiator type, then "other" */
13
- resourceType: string;
14
- navigation: string | null;
15
- /** The request this one is the redirect of, or null */
16
- redirectedFrom: NetworkRequest | null;
17
- /** True while a network intercept holds it */
18
- isBlocked: boolean;
19
- }
20
- export interface NetworkResponse {
21
- url: string;
22
- status: number;
23
- statusText: string;
24
- headers: Record<string, string>;
25
- fromCache: boolean;
26
- request: NetworkRequest;
27
- }
28
- export type FailedRequest = NetworkRequest & {
29
- errorText: string;
30
- };
31
- interface EventMap {
32
- request: [NetworkRequest];
33
- response: [NetworkResponse];
34
- requestfailed: [FailedRequest];
35
- }
36
- export type NetworkEventName = keyof EventMap;
3
+ import { type EventMap, type NetworkEventName, type NetworkRequest } from "./network-types.js";
4
+ export type { FailedRequest, NetworkEventName, NetworkRequest, NetworkResponse, } from "./network-types.js";
5
+ export { NetworkIdleTimeoutError } from "./network-wait.js";
37
6
  export interface TrackerOptions {
38
7
  /** Requests it returns true for are neither counted nor emitted. Default: none */
39
8
  ignore?: (request: NetworkRequest) => boolean;
40
9
  }
41
- /** waitForIdle ran out of time with requests still in flight; `last` holds (up to five of) their URLs */
42
- export declare class NetworkIdleTimeoutError extends WaitTimeoutError<string[]> {
43
- constructor(timeout: number, inflight: number, urls: string[]);
44
- }
45
10
  /**
46
11
  * Follows the network activity of one page (its frames included): which requests are in flight,
47
12
  * and `request` / `response` / `requestfailed` events. In-flight is keyed by `request id:redirect count`,
@@ -53,20 +18,22 @@ export declare class NetworkTracker {
53
18
  private ignore;
54
19
  private connector;
55
20
  private events;
56
- private active;
57
- /** The context each request in flight belongs to, by the same key */
58
- private contexts;
59
- /** Requests that may still be the source of a redirect, by hop key */
21
+ private subscription;
22
+ /**
23
+ * Every hop that is in flight or may still be the source of a redirect, by hop key. A redirect response ends a
24
+ * hop's flight (`live` false) but keeps it, for the next hop's `redirectedFrom`.
25
+ */
60
26
  private hops;
27
+ /** Rejects a pending `waitForIdle`; each wait adds its own */
61
28
  private waiters;
62
29
  private disposed;
63
30
  private constructor();
64
31
  static start(connector: BiDiConnector, tree: ContextTree, contextId: string, options?: TrackerOptions): Promise<NetworkTracker>;
65
- private subscription;
66
32
  /** Requests currently in flight */
67
33
  get inflight(): number;
68
34
  /** URLs of the requests currently in flight, oldest first */
69
35
  get inflightUrls(): string[];
36
+ private liveHops;
70
37
  /** Waits that have not finished yet */
71
38
  get waiting(): number;
72
39
  on<E extends NetworkEventName>(event: E, listener: (...args: EventMap[E]) => void): void;
@@ -95,7 +62,3 @@ export declare class NetworkTracker {
95
62
  /** A listener that throws must not stop the tracker or the other listeners */
96
63
  private emit;
97
64
  }
98
- export declare function toRequest(data: RequestData, navigation: string | null, isBlocked: boolean, redirectedFrom: NetworkRequest | null): NetworkRequest;
99
- /** Header list to a lower-cased record; repeated names are joined, base64 values decoded */
100
- export declare function toHeaders(headers: Header[]): Record<string, string>;
101
- export {};