@itmetsam/samurai-framework 0.10.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 (326) hide show
  1. package/README.md +3 -4
  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 +2 -1
  19. package/dist/browser/dialog-handling.d.ts +32 -0
  20. package/dist/browser/dialog-handling.js +85 -0
  21. package/dist/browser/document-watcher.d.ts +44 -0
  22. package/dist/browser/document-watcher.js +160 -0
  23. package/dist/browser/download-folders.d.ts +0 -1
  24. package/dist/browser/download-folders.js +7 -15
  25. package/dist/browser/download.js +5 -10
  26. package/dist/browser/downloads-dir.js +2 -2
  27. package/dist/browser/emit.d.ts +7 -0
  28. package/dist/browser/emit.js +16 -0
  29. package/dist/browser/emulation.d.ts +1 -1
  30. package/dist/browser/emulation.js +54 -18
  31. package/dist/browser/file-chooser.js +4 -11
  32. package/dist/browser/history.d.ts +6 -0
  33. package/dist/browser/history.js +89 -0
  34. package/dist/browser/index.d.ts +2 -0
  35. package/dist/browser/index.js +2 -0
  36. package/dist/browser/init-script.d.ts +2 -0
  37. package/dist/browser/init-script.js +16 -0
  38. package/dist/browser/launch-firefox.d.ts +20 -0
  39. package/dist/browser/launch-firefox.js +66 -0
  40. package/dist/browser/launch-flags.d.ts +18 -0
  41. package/dist/browser/launch-flags.js +100 -0
  42. package/dist/browser/lazy.d.ts +21 -0
  43. package/dist/browser/lazy.js +44 -0
  44. package/dist/browser/page-events.d.ts +44 -0
  45. package/dist/browser/page-events.js +58 -0
  46. package/dist/browser/page-logs.js +2 -9
  47. package/dist/browser/page-navigation.d.ts +58 -0
  48. package/dist/browser/page-navigation.js +108 -0
  49. package/dist/browser/page-network.d.ts +69 -0
  50. package/dist/browser/page-network.js +163 -0
  51. package/dist/browser/page-settings.d.ts +35 -0
  52. package/dist/browser/page-settings.js +51 -0
  53. package/dist/browser/page-transfers.d.ts +36 -0
  54. package/dist/browser/page-transfers.js +50 -0
  55. package/dist/browser/page.d.ts +39 -154
  56. package/dist/browser/page.js +134 -758
  57. package/dist/browser/pdf.d.ts +1 -1
  58. package/dist/browser/session.d.ts +16 -0
  59. package/dist/browser/session.js +32 -0
  60. package/dist/browser/viewport.d.ts +19 -0
  61. package/dist/browser/viewport.js +72 -0
  62. package/dist/browser/warm-up.d.ts +1 -1
  63. package/dist/browser/warm-up.js +2 -1
  64. package/dist/browsers/index.d.ts +1 -1
  65. package/dist/browsers/index.js +1 -1
  66. package/dist/browsers/pins.d.ts +0 -2
  67. package/dist/browsers/pins.js +0 -2
  68. package/dist/browsers/store.d.ts +0 -2
  69. package/dist/browsers/store.js +1 -2
  70. package/dist/cli/args.d.ts +13 -6
  71. package/dist/cli/args.js +13 -10
  72. package/dist/cli/browsers.d.ts +1 -2
  73. package/dist/cli/browsers.js +2 -2
  74. package/dist/cli/console-reporter.js +3 -2
  75. package/dist/cli/flow-reporter.js +2 -1
  76. package/dist/cli/flow.d.ts +1 -2
  77. package/dist/cli/flow.js +25 -22
  78. package/dist/cli/init.js +2 -7
  79. package/dist/cli/io.d.ts +10 -0
  80. package/dist/cli/io.js +1 -0
  81. package/dist/cli/main.d.ts +3 -10
  82. package/dist/cli/main.js +10 -143
  83. package/dist/cli/paint.d.ts +2 -0
  84. package/dist/cli/paint.js +4 -0
  85. package/dist/cli/record.d.ts +4 -0
  86. package/dist/cli/record.js +93 -0
  87. package/dist/cli/usage.d.ts +1 -0
  88. package/dist/cli/usage.js +58 -0
  89. package/dist/cli/version.d.ts +2 -0
  90. package/dist/cli/version.js +7 -0
  91. package/dist/config/browsers.d.ts +11 -0
  92. package/dist/config/browsers.js +32 -0
  93. package/dist/config/config.js +4 -1
  94. package/dist/config/mask.d.ts +1 -1
  95. package/dist/config/mask.js +7 -2
  96. package/dist/config/run-settings.d.ts +1 -2
  97. package/dist/config/run-settings.js +1 -6
  98. package/dist/config/timeouts.d.ts +2 -0
  99. package/dist/config/timeouts.js +13 -0
  100. package/dist/config/workers.d.ts +14 -0
  101. package/dist/config/workers.js +29 -0
  102. package/dist/flows/run/branch-context.d.ts +14 -0
  103. package/dist/flows/run/branch-context.js +35 -0
  104. package/dist/flows/run/handlers/condition.d.ts +1 -1
  105. package/dist/flows/run/handlers/end.d.ts +1 -1
  106. package/dist/flows/run/handlers/group.d.ts +1 -1
  107. package/dist/flows/run/handlers/index.d.ts +2 -2
  108. package/dist/flows/run/handlers/parallel.d.ts +1 -1
  109. package/dist/flows/run/handlers/start.d.ts +1 -1
  110. package/dist/flows/run/handlers/support.d.ts +3 -27
  111. package/dist/flows/run/handlers/test.d.ts +1 -1
  112. package/dist/flows/run/handlers/types.d.ts +27 -0
  113. package/dist/flows/run/handlers/types.js +1 -0
  114. package/dist/flows/run/index.d.ts +1 -1
  115. package/dist/flows/run/prepare-flow.d.ts +14 -0
  116. package/dist/flows/run/prepare-flow.js +44 -0
  117. package/dist/flows/run/project.d.ts +33 -2
  118. package/dist/flows/run/project.js +139 -57
  119. package/dist/flows/run/run.d.ts +3 -4
  120. package/dist/flows/run/run.js +23 -193
  121. package/dist/flows/run/walker.d.ts +56 -0
  122. package/dist/flows/run/walker.js +225 -0
  123. package/dist/flows/steps/catalog.d.ts +1 -1
  124. package/dist/flows/steps/handler.d.ts +1 -1
  125. package/dist/flows/steps/set.d.ts +1 -1
  126. package/dist/index.js +1 -1
  127. package/dist/locator/actionability.d.ts +33 -0
  128. package/dist/locator/actionability.js +104 -0
  129. package/dist/locator/chain-resolver.d.ts +20 -0
  130. package/dist/locator/chain-resolver.js +102 -0
  131. package/dist/locator/document-swap.d.ts +1 -0
  132. package/dist/locator/document-swap.js +11 -0
  133. package/dist/locator/element-state.d.ts +3 -1
  134. package/dist/locator/element-state.js +11 -3
  135. package/dist/locator/file-actions.d.ts +35 -0
  136. package/dist/locator/file-actions.js +55 -0
  137. package/dist/{script/helpers.js → locator/helper-realm.js} +2 -2
  138. package/dist/locator/input-actions.d.ts +18 -0
  139. package/dist/locator/input-actions.js +80 -0
  140. package/dist/locator/label-locator.d.ts +1 -1
  141. package/dist/locator/label-locator.js +5 -12
  142. package/dist/locator/locator.d.ts +14 -37
  143. package/dist/locator/locator.js +68 -424
  144. package/dist/locator/page-scripts.d.ts +16 -0
  145. package/dist/locator/page-scripts.js +54 -0
  146. package/dist/locator/page-search.d.ts +10 -0
  147. package/dist/locator/page-search.js +19 -0
  148. package/dist/locator/selector-errors.d.ts +0 -4
  149. package/dist/locator/selector-errors.js +0 -7
  150. package/dist/locator/selector.d.ts +14 -13
  151. package/dist/locator/selector.js +10 -16
  152. package/dist/locator/text-locator.d.ts +1 -1
  153. package/dist/locator/text-locator.js +5 -9
  154. package/dist/logger/index.d.ts +6 -0
  155. package/dist/logger/index.js +14 -7
  156. package/dist/network/bidi-wire.d.ts +10 -0
  157. package/dist/network/bidi-wire.js +38 -0
  158. package/dist/network/intercept.d.ts +30 -0
  159. package/dist/network/intercept.js +130 -0
  160. package/dist/network/network-tracker.d.ts +10 -47
  161. package/dist/network/network-tracker.js +34 -68
  162. package/dist/network/network-types.d.ts +33 -0
  163. package/dist/network/network-types.js +1 -0
  164. package/dist/network/network-wait.d.ts +7 -2
  165. package/dist/network/network-wait.js +14 -4
  166. package/dist/network/response.d.ts +1 -1
  167. package/dist/network/response.js +1 -1
  168. package/dist/network/route.d.ts +92 -0
  169. package/dist/network/route.js +142 -0
  170. package/dist/network/router.d.ts +6 -91
  171. package/dist/network/router.js +25 -258
  172. package/dist/recorder/expectation.d.ts +5 -0
  173. package/dist/recorder/expectation.js +20 -0
  174. package/dist/recorder/files-recorder.d.ts +30 -0
  175. package/dist/recorder/files-recorder.js +88 -0
  176. package/dist/recorder/normalise.d.ts +17 -6
  177. package/dist/recorder/normalise.js +96 -91
  178. package/dist/recorder/options.d.ts +56 -0
  179. package/dist/recorder/options.js +1 -0
  180. package/dist/recorder/page-messages.d.ts +35 -0
  181. package/dist/recorder/page-messages.js +26 -0
  182. package/dist/recorder/ranking.js +1 -0
  183. package/dist/recorder/realms.d.ts +6 -0
  184. package/dist/recorder/realms.js +13 -0
  185. package/dist/recorder/recorder.d.ts +10 -74
  186. package/dist/recorder/recorder.js +39 -199
  187. package/dist/recorder/session-browser.d.ts +22 -0
  188. package/dist/recorder/session-browser.js +21 -0
  189. package/dist/recorder/session-secrets.d.ts +8 -0
  190. package/dist/recorder/session-secrets.js +45 -0
  191. package/dist/recorder/session.d.ts +5 -14
  192. package/dist/recorder/session.js +22 -120
  193. package/dist/recorder/spec-source.d.ts +39 -0
  194. package/dist/recorder/spec-source.js +84 -0
  195. package/dist/recorder/toolbar/action-guard.d.ts +21 -0
  196. package/dist/recorder/toolbar/action-guard.js +43 -0
  197. package/dist/recorder/toolbar/actions/assert.d.ts +4 -0
  198. package/dist/recorder/toolbar/actions/assert.js +52 -0
  199. package/dist/recorder/toolbar/actions/insert.d.ts +6 -0
  200. package/dist/recorder/toolbar/actions/insert.js +93 -0
  201. package/dist/recorder/toolbar/actions/pick.d.ts +8 -0
  202. package/dist/recorder/toolbar/actions/pick.js +26 -0
  203. package/dist/recorder/toolbar/actions/reply.d.ts +7 -0
  204. package/dist/recorder/toolbar/actions/reply.js +10 -0
  205. package/dist/recorder/toolbar/controller-fixture.d.ts +47 -0
  206. package/dist/recorder/toolbar/controller-fixture.js +129 -0
  207. package/dist/recorder/toolbar/controller.d.ts +12 -78
  208. package/dist/recorder/toolbar/controller.js +35 -247
  209. package/dist/recorder/toolbar/inspect.d.ts +1 -3
  210. package/dist/recorder/toolbar/inspect.js +2 -2
  211. package/dist/recorder/toolbar/page-scope.d.ts +19 -0
  212. package/dist/recorder/toolbar/page-scope.js +43 -0
  213. package/dist/recorder/toolbar/protocol.d.ts +2 -1
  214. package/dist/recorder/toolbar/source/attach.d.ts +2 -0
  215. package/dist/recorder/toolbar/source/attach.js +41 -0
  216. package/dist/recorder/toolbar/source/dom.d.ts +2 -0
  217. package/dist/recorder/toolbar/source/dom.js +47 -0
  218. package/dist/recorder/toolbar/source/drag.d.ts +2 -0
  219. package/dist/recorder/toolbar/source/drag.js +32 -0
  220. package/dist/recorder/toolbar/source/events-page.d.ts +2 -0
  221. package/dist/recorder/toolbar/source/events-page.js +67 -0
  222. package/dist/recorder/toolbar/source/events-toolbar.d.ts +2 -0
  223. package/dist/recorder/toolbar/source/events-toolbar.js +35 -0
  224. package/dist/recorder/toolbar/source/fields.d.ts +2 -0
  225. package/dist/recorder/toolbar/source/fields.js +44 -0
  226. package/dist/recorder/toolbar/source/handlers.d.ts +2 -0
  227. package/dist/recorder/toolbar/source/handlers.js +134 -0
  228. package/dist/recorder/toolbar/source/names.d.ts +2 -0
  229. package/dist/recorder/toolbar/source/names.js +12 -0
  230. package/dist/recorder/toolbar/source/picking.d.ts +2 -0
  231. package/dist/recorder/toolbar/source/picking.js +72 -0
  232. package/dist/recorder/toolbar/source/placement.d.ts +2 -0
  233. package/dist/recorder/toolbar/source/placement.js +45 -0
  234. package/dist/recorder/toolbar/source/recorder-side.d.ts +2 -0
  235. package/dist/recorder/toolbar/source/recorder-side.js +54 -0
  236. package/dist/recorder/toolbar/source/setup.d.ts +2 -0
  237. package/dist/recorder/toolbar/source/setup.js +50 -0
  238. package/dist/recorder/toolbar/source/views-panels.d.ts +2 -0
  239. package/dist/recorder/toolbar/source/views-panels.js +150 -0
  240. package/dist/recorder/toolbar/source/views-rail.d.ts +2 -0
  241. package/dist/recorder/toolbar/source/views-rail.js +40 -0
  242. package/dist/recorder/toolbar/source/views-render.d.ts +2 -0
  243. package/dist/recorder/toolbar/source/views-render.js +48 -0
  244. package/dist/recorder/toolbar/source.js +30 -856
  245. package/dist/recorder/toolbar/types.d.ts +70 -0
  246. package/dist/recorder/toolbar/types.js +1 -0
  247. package/dist/recorder/toolbar-bridge.d.ts +43 -0
  248. package/dist/recorder/toolbar-bridge.js +106 -0
  249. package/dist/runner/browsers.d.ts +0 -12
  250. package/dist/runner/browsers.js +1 -33
  251. package/dist/runner/options.d.ts +31 -0
  252. package/dist/runner/options.js +1 -0
  253. package/dist/runner/pooled-run.d.ts +43 -0
  254. package/dist/runner/pooled-run.js +75 -0
  255. package/dist/runner/ports.d.ts +2 -0
  256. package/dist/runner/ports.js +2 -0
  257. package/dist/runner/registry.d.ts +1 -1
  258. package/dist/runner/registry.js +1 -1
  259. package/dist/runner/reporter.d.ts +31 -10
  260. package/dist/runner/reporter.js +39 -6
  261. package/dist/runner/run-test.d.ts +16 -0
  262. package/dist/runner/run-test.js +178 -0
  263. package/dist/runner/run.d.ts +5 -3
  264. package/dist/runner/run.js +28 -29
  265. package/dist/runner/select.d.ts +24 -0
  266. package/dist/runner/select.js +77 -0
  267. package/dist/runner/test-dir.d.ts +13 -0
  268. package/dist/runner/test-dir.js +27 -0
  269. package/dist/runner/test-runner.d.ts +25 -56
  270. package/dist/runner/test-runner.js +81 -270
  271. package/dist/runner/worker-pool.d.ts +67 -0
  272. package/dist/runner/worker-pool.js +275 -0
  273. package/dist/runner/worker-process.d.ts +6 -0
  274. package/dist/runner/worker-process.js +54 -0
  275. package/dist/runner/worker-protocol.d.ts +67 -0
  276. package/dist/runner/worker-protocol.js +1 -0
  277. package/dist/runner/worker-session.d.ts +7 -0
  278. package/dist/runner/worker-session.js +60 -0
  279. package/dist/runner/worker.d.ts +26 -0
  280. package/dist/runner/worker.js +121 -0
  281. package/dist/runner/workers-option.d.ts +15 -0
  282. package/dist/runner/workers-option.js +22 -0
  283. package/dist/script/call-function.d.ts +1 -9
  284. package/dist/script/call-function.js +2 -19
  285. package/dist/script/element-handle.d.ts +1 -2
  286. package/dist/script/element-handle.js +1 -2
  287. package/dist/script/serialize.d.ts +3 -12
  288. package/dist/script/serialize.js +53 -62
  289. package/dist/steps/parse/call.d.ts +3 -0
  290. package/dist/steps/parse/call.js +81 -0
  291. package/dist/steps/parse/expectation.d.ts +5 -0
  292. package/dist/steps/parse/expectation.js +71 -0
  293. package/dist/steps/parse/file-entry.d.ts +4 -0
  294. package/dist/steps/parse/file-entry.js +74 -0
  295. package/dist/steps/parse/literals.d.ts +4 -0
  296. package/dist/steps/parse/literals.js +28 -0
  297. package/dist/steps/parse/step.d.ts +4 -0
  298. package/dist/steps/parse/step.js +81 -0
  299. package/dist/steps/parse.js +2 -323
  300. package/dist/transport/bidi-connection.d.ts +4 -15
  301. package/dist/transport/bidi-connection.js +9 -63
  302. package/dist/transport/log-redaction.d.ts +13 -0
  303. package/dist/transport/log-redaction.js +51 -0
  304. package/dist/transport/subscriptions.js +18 -13
  305. package/dist/transport/unsupported.d.ts +7 -0
  306. package/dist/transport/unsupported.js +13 -0
  307. package/dist/types/bidi-modules/browser.d.ts +1 -12
  308. package/dist/types/bidi-modules/browsing-context.d.ts +8 -18
  309. package/dist/types/bidi-modules/emulation.d.ts +29 -21
  310. package/dist/types/bidi-modules/input.d.ts +1 -9
  311. package/dist/types/bidi-modules/network.d.ts +29 -24
  312. package/dist/types/bidi-modules/script.d.ts +0 -9
  313. package/dist/types/bidi-modules/session.d.ts +0 -8
  314. package/dist/types/bidi-modules/storage.d.ts +0 -5
  315. package/dist/types/bidi.d.ts +7 -37
  316. package/dist/types/config.d.ts +12 -0
  317. package/dist/types/test.d.ts +8 -3
  318. package/dist/wait/wait-until.d.ts +1 -5
  319. package/dist/wait/wait-until.js +7 -16
  320. package/package.json +3 -2
  321. package/dist/config/default.d.ts +0 -2
  322. package/dist/config/default.js +0 -3
  323. package/dist/types/bidi-modules/web-extensions.d.ts +0 -9
  324. package/dist/types/bidi-protocols/command.d.ts +0 -7
  325. package/dist/types/bidi-protocols/event.d.ts +0 -17
  326. /package/dist/{script/helpers.d.ts → locator/helper-realm.d.ts} +0 -0
@@ -0,0 +1,54 @@
1
+ /** The recorder's side of the hook: update, reply, rebind, dispose. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export const RECORDER_SIDE_JS = String.raw ` // ---- The recorder's side ----
3
+ const showToast = (text) => {
4
+ toast.textContent = text;
5
+ toast.hidden = false;
6
+ toast.classList.remove("gone");
7
+ clearTimeout(toastTimer);
8
+ toastTimer = setTimeout(() => {
9
+ toast.classList.add("gone");
10
+ toastTimer = setTimeout(() => { toast.hidden = true; }, 300);
11
+ }, 2500);
12
+ };
13
+ const update = (next) => {
14
+ state = Object.assign({}, DEFAULTS, next);
15
+ const dropped = ui.dropped;
16
+ if (dropped && state.position && Math.round(state.position.x) === dropped.x && Math.round(state.position.y) === dropped.y) ui.dropped = null;
17
+ if (ui.closeOnUpdate) closePanel();
18
+ if (!usable()) {
19
+ stopPicking();
20
+ closePanel();
21
+ }
22
+ if (state.toast && state.toast.id !== ui.toastId) {
23
+ ui.toastId = state.toast.id;
24
+ showToast(state.toast.text);
25
+ }
26
+ attach();
27
+ render();
28
+ };
29
+ const reply = (id, result) => {
30
+ if (!ui.pending || id !== ui.pending || !result) return;
31
+ ui.busy = false;
32
+ const ok = result.ok === true;
33
+ if (ui.panel === "assert" && ui.assert && !ui.assert.info) {
34
+ const a = ui.assert;
35
+ a.info = result;
36
+ if (ok) {
37
+ a.matcher = result.first.matcher;
38
+ a.attribute = result.attributes[0] ? result.attributes[0].name : null;
39
+ a.countIndex = 0;
40
+ a.expected = prefill(a, a.matcher);
41
+ }
42
+ } else if (ok) {
43
+ closePanel();
44
+ } else if (ui.panel === "assert" && ui.assert) {
45
+ ui.assert.error = result.error;
46
+ } else if (ui.panel === "insert") {
47
+ ui.insert.error = result.error;
48
+ } else if (ui.panel === "new") {
49
+ if (result.field === "name") ui.form.nameError = result.error;
50
+ else ui.form.error = result.error;
51
+ }
52
+ render();
53
+ };
54
+ `;
@@ -0,0 +1,2 @@
1
+ /** Preamble: single-run guard, shared candidate code, styles, defaults and the toolbar state variables. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export declare const SETUP_JS: string;
@@ -0,0 +1,50 @@
1
+ import { CANDIDATES_JS } from "../../candidates.js";
2
+ import { TOOLBAR_KEY } from "../protocol.js";
3
+ import { TOOLBAR_CSS } from "../styles.js";
4
+ /** Preamble: single-run guard, shared candidate code, styles, defaults and the toolbar state variables. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
5
+ export const SETUP_JS = String.raw ` if (window !== window.top) return;
6
+ const KEY = Symbol.for("${TOOLBAR_KEY}");
7
+ if (globalThis[KEY]) {
8
+ globalThis[KEY].rebind(send);
9
+ return;
10
+ }
11
+
12
+ ${CANDIDATES_JS}
13
+
14
+ const CSS = ${JSON.stringify(TOOLBAR_CSS)};
15
+ const DEFAULTS = {
16
+ status: "recording", collapsed: false, position: null, steps: 0, environment: "", canAddVariables: false,
17
+ variables: [], secrets: [], secretsIgnored: true, resumeQuestion: false, nextScreenshot: "screenshot-1",
18
+ warnings: [],
19
+ };
20
+ const MATCHERS = [
21
+ ["toBeVisible", "Visible"], ["toHaveText", "Has text"], ["toContainText", "Contains text"],
22
+ ["toHaveValue", "Has value"], ["toHaveAttribute", "Has attribute"], ["toHaveCount", "Count"],
23
+ ];
24
+
25
+ let channel = send;
26
+ let state = Object.assign({}, DEFAULTS);
27
+ let nextId = Date.now();
28
+ let railBox = { x: 0, y: 0, w: 0, h: 0 };
29
+ let toastTimer = 0;
30
+ // Local UI state; everything about steps lives in the recorder
31
+ const ui = {
32
+ panel: null, picking: false, busy: false, closeOnUpdate: false, pending: 0, focus: null,
33
+ field: null, assert: null, insert: null, form: null,
34
+ wait: { kind: "idle", seconds: "2" }, shot: { name: "", fullPage: false },
35
+ drag: null, dropped: null, toastId: null,
36
+ };
37
+
38
+ const post = (message) => {
39
+ try { channel(Object.assign({ type: "toolbar" }, message)); } catch (err) { /* the channel is gone */ }
40
+ };
41
+ // Listeners on the page's window and document, so dispose() can take them all off again
42
+ const listening = [];
43
+ const listen = (target, type, handler, capture) => {
44
+ target.addEventListener(type, handler, capture === true);
45
+ listening.push([target, type, handler, capture === true]);
46
+ };
47
+ const paused = () => state.status === "paused";
48
+ // Whole pixels, so a rail at the far edge does not overhang it by a rounding error
49
+ const clamp = (value, max) => Math.max(0, Math.min(value, Math.floor(max)));
50
+ `;
@@ -0,0 +1,2 @@
1
+ /** Views: the Assert, Insert, New, Wait and Screenshot panels. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export declare const VIEWS_PANELS_JS: string;
@@ -0,0 +1,150 @@
1
+ /** Views: the Assert, Insert, New, Wait and Screenshot panels. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export const VIEWS_PANELS_JS = String.raw ` const unavailable = (info, matcher) =>
3
+ (matcher === "toHaveValue" && info.value === undefined) ||
4
+ (matcher === "toHaveAttribute" && info.attributes.length === 0) ||
5
+ (matcher === "toHaveCount" && info.counts.length === 0);
6
+ const prefill = (a, matcher) => {
7
+ const info = a.info;
8
+ if (matcher === "toHaveAttribute") {
9
+ const found = info.attributes.find((at) => at.name === a.attribute) || info.attributes[0];
10
+ return found ? found.value : "";
11
+ }
12
+ if (matcher === "toHaveCount") {
13
+ const found = info.counts[a.countIndex];
14
+ return found ? String(found.count) : "";
15
+ }
16
+ if (matcher === info.first.matcher && info.first.expected !== undefined) return info.first.expected;
17
+ if (matcher === "toHaveText" || matcher === "toContainText") return info.text;
18
+ if (matcher === "toHaveValue") return info.value || "";
19
+ return "";
20
+ };
21
+ const assertValue = (a) => {
22
+ const info = a.info;
23
+ const expected = (type) => h("input", { type, class: "in", "data-field": "expected", value: a.expected, "data-enter": "assert-add", autocomplete: "off" });
24
+ if (a.matcher === "toHaveText" || a.matcher === "toContainText" || a.matcher === "toHaveValue") return h("div", { class: "val" }, expected("text"));
25
+ if (a.matcher === "toHaveAttribute") {
26
+ return h("div", { class: "val" },
27
+ h("select", { class: "in", "data-field": "attribute" }, info.attributes.map((at) => {
28
+ const shown = at.name + '="' + at.value + '"';
29
+ return h("option", { value: at.name, selected: at.name === a.attribute }, shown.length > 44 ? shown.slice(0, 43) + "…" : shown);
30
+ })),
31
+ expected("text"));
32
+ }
33
+ if (a.matcher === "toHaveCount") {
34
+ return h("div", { class: "val" },
35
+ h("select", { class: "in", "data-field": "countIndex" }, info.counts.map((c, i) =>
36
+ h("option", { value: String(i), selected: i === a.countIndex }, c.label + " (" + c.count + ")"))),
37
+ expected("number"));
38
+ }
39
+ return null;
40
+ };
41
+ const assertPanel = () => {
42
+ const a = ui.assert;
43
+ const info = a.info;
44
+ const head = h("div", { class: "h" }, "Assert", info && info.ok && h("code", { title: info.label }, info.label));
45
+ if (!info) return [head, h("div", { class: "msg" }, "…")];
46
+ if (!info.ok) return [head, h("div", { class: "err" }, info.error)];
47
+ return [
48
+ head,
49
+ h("div", { class: "opts" }, MATCHERS.map(([matcher, label]) =>
50
+ h("button", { class: a.matcher === matcher ? "o sel" : "o", "data-action": "matcher", "data-matcher": matcher, disabled: unavailable(info, matcher) }, label))),
51
+ assertValue(a),
52
+ a.error && h("div", { class: "err" }, a.error),
53
+ h("div", { class: "row" },
54
+ h("label", { class: "neg" }, h("input", { type: "checkbox", "data-action": "not", checked: a.not }), "Not"),
55
+ h("button", { class: "add", "data-action": "assert-add", disabled: ui.busy }, "Add")),
56
+ ];
57
+ };
58
+
59
+ const matches = () => {
60
+ const filter = ui.insert.filter.trim().toLowerCase();
61
+ const hit = (item) => !filter || item.name.toLowerCase().indexOf(filter) >= 0;
62
+ return {
63
+ filter,
64
+ variables: state.canAddVariables ? state.variables.filter(hit) : [],
65
+ secrets: state.secrets.filter(hit),
66
+ };
67
+ };
68
+ const insertPanel = () => {
69
+ const ins = ui.insert;
70
+ if (!ins.field) return [h("div", { class: "h" }, "Insert"), h("div", { class: "msg" }, "Click into a field first")];
71
+ const found = matches();
72
+ const none = found.filter && found.variables.length === 0 && found.secrets.length === 0;
73
+ const item = (kind, name, value) =>
74
+ h("button", { class: "it", "data-action": "insert-item", "data-kind": kind, "data-name": name, disabled: ui.busy }, h("code", null, name), value);
75
+ return [
76
+ h("div", { class: "h stack" }, 'Insert into "' + fieldLabel(ins.field) + '"', h("small", null, "Environment: " + state.environment)),
77
+ h("input", { type: "text", class: "in search", "data-field": "filter", placeholder: "Filter…", value: ins.filter, "data-enter": "insert-first", autocomplete: "off", spellcheck: "false" }),
78
+ state.canAddVariables && [
79
+ h("div", { class: "grp" }, "Variables"),
80
+ found.variables.length
81
+ ? found.variables.map((v) => item("env", v.name, h("span", { class: "v", title: v.value }, v.value)))
82
+ : h("div", { class: "empty" }, found.filter ? "No variable matches." : "No variables yet."),
83
+ ],
84
+ h("div", { class: "grp" }, "Secrets"),
85
+ found.secrets.length
86
+ ? found.secrets.map((s) => item("secret", s.name, s.set ? h("span", { class: "v" }, "••••••") : h("span", { class: "warn" }, "not set")))
87
+ : h("div", { class: "empty" }, found.filter ? "No secret matches." : "No secrets yet."),
88
+ ins.error && h("div", { class: "err" }, ins.error),
89
+ h("button", { class: "act", "data-action": "insert-new", "data-kind": "env" }, "+ Add variable" + (none ? ' "' + variableName(ins.filter) + '"' : "")),
90
+ h("button", { class: "act", "data-action": "insert-new", "data-kind": "secret" }, "+ Add secret" + (none ? ' "' + snake(ins.filter) + '"' : "")),
91
+ ];
92
+ };
93
+
94
+ const newHint = (secret, env, name) => {
95
+ if (!secret) return ["Saved to ", h("code", null, "environments." + env + ".variables"), " in samurai.config.ts. Other environments don't get it — add it there before running against them."];
96
+ if (!state.secretsIgnored) return h("span", { class: "warn" }, "Add .env." + env + " to .gitignore before committing.");
97
+ return ["Saved as ", h("code", null, "SAMURAI_SECRET_" + (name.trim() || "<NAME>")), " in ", h("code", null, ".env." + env), " (git-ignored)."];
98
+ };
99
+ const newPanel = () => {
100
+ const f = ui.form;
101
+ const secret = f.kind === "secret";
102
+ const blocked = !secret && !state.canAddVariables;
103
+ const env = state.environment;
104
+ return [
105
+ h("div", { class: "h stack" }, f.setValue ? "Set value" : secret ? "New secret" : "New variable", h("small", null, 'For "' + fieldLabel(ui.insert.field) + '"')),
106
+ h("div", { class: "seg" },
107
+ h("button", { class: secret ? "" : "sel", "data-action": "new-kind", "data-kind": "env" }, "Variable"),
108
+ h("button", { class: secret ? "sel" : "", "data-action": "new-kind", "data-kind": "secret" }, "Secret")),
109
+ blocked
110
+ ? h("div", { class: "msg" }, "This recording has no environment")
111
+ : [
112
+ h("div", { class: "lbl" }, "Name"),
113
+ h("div", { class: "f" }, h("input", { type: "text", class: "in code", "data-field": "name", value: f.name, "data-enter": "new-save", autocomplete: "off", spellcheck: "false" })),
114
+ f.nameError && h("div", { class: "field-error" }, f.nameError),
115
+ h("div", { class: "lbl" }, "Value in " + env),
116
+ h("div", { class: "f" }, h("input", { type: secret ? "password" : "text", class: "in", "data-field": "value", value: f.value, "data-enter": "new-save", autocomplete: secret ? "new-password" : "off" })),
117
+ h("div", { class: "hint" }, newHint(secret, env, f.name)),
118
+ f.error && h("div", { class: "err" }, f.error),
119
+ ],
120
+ h("div", { class: "foot plain" },
121
+ h("button", { class: "cancel", "data-action": "new-cancel" }, "Cancel"),
122
+ !blocked && h("button", { class: "add", "data-action": "new-save", disabled: ui.busy || !f.name.trim() }, "Save and insert")),
123
+ ];
124
+ };
125
+
126
+ const secondsValid = () => {
127
+ const seconds = Number(ui.wait.seconds);
128
+ return ui.wait.seconds.trim() !== "" && isFinite(seconds) && seconds >= 0.1 && seconds <= 60;
129
+ };
130
+ const radio = (field, value, checked, ...label) =>
131
+ h("label", { class: "radio" }, h("input", { type: "radio", name: field, "data-field": field, value, checked }), label);
132
+ const waitPanel = () => [
133
+ h("div", { class: "h" }, "Wait"),
134
+ radio("waitKind", "idle", ui.wait.kind === "idle", "Until the page settles"),
135
+ h("div", { class: "sub" }, "No requests for 500 ms"),
136
+ radio("waitKind", "time", ui.wait.kind === "time", "For ",
137
+ h("input", { type: "number", class: "num", "data-field": "seconds", min: "0.1", max: "60", step: "0.1", value: ui.wait.seconds, "data-enter": "wait-add" }),
138
+ " seconds"),
139
+ h("div", { class: "foot" }, h("button", { class: "add", "data-action": "wait-add", disabled: ui.busy || (ui.wait.kind === "time" && !secondsValid()) }, "Add")),
140
+ ];
141
+ const screenshotPanel = () => [
142
+ h("div", { class: "h" }, "Screenshot"),
143
+ h("div", { class: "grp" }, "Name"),
144
+ h("div", { class: "f" }, h("input", { type: "text", class: "in", "data-field": "shotName", value: ui.shot.name, "data-enter": "screenshot-add", autocomplete: "off", spellcheck: "false" })),
145
+ radio("fullPage", "false", !ui.shot.fullPage, "Visible part"),
146
+ radio("fullPage", "true", ui.shot.fullPage, "Whole page"),
147
+ h("div", { class: "foot" }, h("button", { class: "add", "data-action": "screenshot-add", disabled: ui.busy }, "Add")),
148
+ ];
149
+ const PANELS = { assert: assertPanel, insert: insertPanel, new: newPanel, wait: waitPanel, screenshot: screenshotPanel };
150
+ `;
@@ -0,0 +1,2 @@
1
+ /** Views: the chip and the rail. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export declare const VIEWS_RAIL_JS: string;
@@ -0,0 +1,40 @@
1
+ /** Views: the chip and the rail. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export const VIEWS_RAIL_JS = String.raw ` // ---- Views ----
3
+ const toolOn = (tool) =>
4
+ tool === "assert" ? ui.picking || ui.panel === "assert" : tool === "insert" ? ui.panel === "insert" || ui.panel === "new" : ui.panel === tool;
5
+
6
+ const chipView = () =>
7
+ h("div", { class: "chip" },
8
+ h("span", { "data-grip": true, title: "Drag to move" }, "⋮⋮"),
9
+ h("span", { class: paused() ? "dot pause" : "dot" }),
10
+ (paused() ? "Paused" : "Rec") + " · " + state.steps + (state.steps === 1 ? " step" : " steps"),
11
+ h("button", { class: "chev", "data-action": "expand", title: "Expand" }, "⌄"));
12
+
13
+ const railView = () => {
14
+ const tool = (action, icon, label) =>
15
+ h("button", { class: toolOn(action) ? "b on" : "b", "data-action": action, disabled: paused() }, ico(icon), label);
16
+ return h("div", { class: paused() || state.resumeQuestion ? "rail wide" : "rail" },
17
+ h("div", { class: "top" },
18
+ h("span", { "data-grip": true, title: "Drag to move" }, "⋮⋮⋮"),
19
+ h("button", { class: "chev", "data-action": "collapse", title: "Collapse" }, "⌃")),
20
+ h("div", { class: "st" }, h("span", { class: paused() ? "dot pause" : "dot" }), paused() ? "Paused" : "Recording"),
21
+ paused() && h("div", { class: "note" }, "Nothing you do now is recorded."),
22
+ state.resumeQuestion && [
23
+ h("div", { class: "note" }, "Add a step that opens this page?"),
24
+ h("div", { class: "ask" },
25
+ h("button", { class: "yes", "data-action": "resume-yes" }, "Yes"),
26
+ h("button", { "data-action": "resume-no" }, "No")),
27
+ ],
28
+ h("div", { class: "sep" }),
29
+ paused()
30
+ ? h("button", { class: "b on", "data-action": "resume" }, ico("▶"), "Resume")
31
+ : h("button", { class: "b", "data-action": "pause" }, ico("❚❚"), "Pause"),
32
+ tool("assert", "✓", "Assert"),
33
+ ui.picking && h("div", { class: "note" }, "Click an element · Esc cancels"),
34
+ tool("insert", "{x}", "Insert"),
35
+ tool("wait", "⏱", "Wait"),
36
+ tool("screenshot", "◉", "Screenshot"),
37
+ h("div", { class: "sep" }),
38
+ h("button", { class: "b stop", "data-action": "stop" }, ico("■"), "Stop"));
39
+ };
40
+ `;
@@ -0,0 +1,2 @@
1
+ /** Views: warnings, notices and the render pass. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export declare const VIEWS_RENDER_JS: string;
@@ -0,0 +1,48 @@
1
+ /** Views: warnings, notices and the render pass. A slice of the toolbar function: it shares one closure with its neighbours, see `../source.ts`. */
2
+ export const VIEWS_RENDER_JS = String.raw ` // Notice nodes live as long as their warning: rebuilding them would make screen readers announce each alert again
3
+ const noticeNodes = new Map();
4
+ let savingNode = null;
5
+ let savingText = null;
6
+ const renderNotices = () => {
7
+ const ids = new Set(state.warnings.map((w) => w.id));
8
+ for (const [id, node] of noticeNodes) {
9
+ if (ids.has(id)) continue;
10
+ node.remove();
11
+ noticeNodes.delete(id);
12
+ }
13
+ for (const w of state.warnings) {
14
+ if (noticeNodes.has(w.id)) continue;
15
+ const node = h("div", { class: "notice warning", "data-warning": String(w.id), role: "alert" },
16
+ h("span", null, w.text),
17
+ h("button", { class: "dismiss", "data-action": "dismiss", "data-id": String(w.id) }, "Dismiss"));
18
+ noticeNodes.set(w.id, node);
19
+ // Before the saving line, which stays last
20
+ notices.insertBefore(node, savingNode);
21
+ }
22
+ const saving = state.saving || null;
23
+ if (saving !== savingText) {
24
+ savingText = saving;
25
+ if (savingNode) savingNode.remove();
26
+ savingNode = saving ? h("div", { class: "notice saving" }, "Saving " + saving + "…") : null;
27
+ if (savingNode) notices.append(savingNode);
28
+ }
29
+ };
30
+ const render = () => {
31
+ const active = root.activeElement;
32
+ const kept = active && active.type !== "radio" ? active.getAttribute("data-field") : null;
33
+ let selection = null;
34
+ try { selection = kept ? [active.selectionStart, active.selectionEnd] : null; } catch (err) { selection = null; }
35
+ const panel = ui.panel && !state.collapsed ? h("div", { class: ui.panel === "new" || ui.panel === "insert" ? "panel wide" : "panel" }, PANELS[ui.panel]()) : null;
36
+ container.replaceChildren(state.collapsed ? chipView() : railView(), ...(panel ? [panel] : []));
37
+ renderNotices();
38
+ placeAll();
39
+ const focus = ui.focus || kept;
40
+ ui.focus = null;
41
+ const target = focus && root.querySelector('[data-field="' + focus + '"]');
42
+ if (!target) return;
43
+ target.focus({ preventScroll: true });
44
+ if (focus === kept && selection && selection[0] !== null) {
45
+ try { target.setSelectionRange(selection[0], selection[1]); } catch (err) { /* not a text input */ }
46
+ }
47
+ };
48
+ `;