@itmetsam/samurai-framework 0.1.0 → 0.2.1
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.
- package/README.md +129 -0
- package/bin/samurai.mjs +31 -0
- package/dist/api.js +3 -0
- package/dist/assert/assertion-error.d.ts +23 -0
- package/dist/assert/assertion-error.js +45 -0
- package/dist/assert/expect.d.ts +55 -0
- package/dist/assert/expect.js +188 -0
- package/dist/browser/browser-context.d.ts +91 -0
- package/dist/browser/browser-context.js +146 -0
- package/dist/browser/browser-finder.d.ts +2 -0
- package/dist/browser/browser-finder.js +95 -0
- package/dist/browser/browser.d.ts +95 -0
- package/dist/browser/browser.js +372 -0
- package/dist/browser/context-tree.d.ts +23 -0
- package/dist/browser/context-tree.js +60 -0
- package/dist/browser/dialog.d.ts +37 -0
- package/dist/browser/dialog.js +61 -0
- package/dist/browser/download.d.ts +71 -0
- package/dist/browser/download.js +137 -0
- package/dist/browser/downloads-dir.d.ts +8 -0
- package/dist/browser/downloads-dir.js +38 -0
- package/dist/browser/emulation.d.ts +61 -0
- package/dist/browser/emulation.js +144 -0
- package/dist/browser/file-chooser.d.ts +39 -0
- package/dist/browser/file-chooser.js +86 -0
- package/dist/browser/file-paths.d.ts +4 -0
- package/dist/browser/file-paths.js +18 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.js +4 -0
- package/dist/browser/navigation-error.d.ts +13 -0
- package/dist/browser/navigation-error.js +19 -0
- package/dist/browser/page-logs.d.ts +86 -0
- package/dist/browser/page-logs.js +149 -0
- package/dist/browser/page-wait.d.ts +9 -0
- package/dist/browser/page-wait.js +17 -0
- package/dist/browser/page.d.ts +370 -0
- package/dist/browser/page.js +1038 -0
- package/dist/browser/pdf.d.ts +72 -0
- package/dist/browser/pdf.js +37 -0
- package/dist/browser/screenshot.d.ts +29 -0
- package/dist/browser/screenshot.js +42 -0
- package/dist/cli/args.d.ts +35 -0
- package/dist/cli/args.js +69 -0
- package/dist/cli/cli.cli-test.d.ts +1 -0
- package/dist/cli/cli.cli-test.js +170 -0
- package/dist/cli/console-reporter.d.ts +15 -0
- package/dist/cli/console-reporter.js +52 -0
- package/dist/cli/init.d.ts +7 -0
- package/dist/cli/init.js +61 -0
- package/dist/cli/main.d.ts +12 -0
- package/dist/cli/main.js +156 -0
- package/dist/config/config.d.ts +24 -0
- package/dist/config/config.js +42 -0
- package/dist/config/default.d.ts +2 -0
- package/dist/config/default.js +3 -0
- package/dist/config/mask.d.ts +11 -0
- package/dist/config/mask.js +85 -0
- package/dist/config/run-settings.d.ts +28 -0
- package/dist/config/run-settings.js +61 -0
- package/dist/config/secrets.d.ts +10 -0
- package/dist/config/secrets.js +67 -0
- package/dist/config/variables.d.ts +11 -0
- package/dist/config/variables.js +26 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/locator/action-timeout-error.d.ts +25 -0
- package/dist/locator/action-timeout-error.js +35 -0
- package/dist/locator/element-state.d.ts +44 -0
- package/dist/locator/element-state.js +109 -0
- package/dist/locator/label-locator.d.ts +13 -0
- package/dist/locator/label-locator.js +49 -0
- package/dist/locator/locator.d.ts +168 -0
- package/dist/locator/locator.js +591 -0
- package/dist/locator/selector-errors.d.ts +9 -0
- package/dist/locator/selector-errors.js +15 -0
- package/dist/locator/selector.d.ts +60 -0
- package/dist/locator/selector.js +113 -0
- package/dist/locator/text-locator.d.ts +13 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.js +30 -0
- package/dist/network/data-collector.d.ts +26 -0
- package/dist/network/data-collector.js +77 -0
- package/dist/network/network-tracker.d.ts +94 -0
- package/dist/network/network-tracker.js +198 -0
- package/dist/network/network-wait.d.ts +16 -0
- package/dist/network/network-wait.js +24 -0
- package/dist/network/response.d.ts +22 -0
- package/dist/network/response.js +42 -0
- package/dist/network/router.d.ts +120 -0
- package/dist/network/router.js +343 -0
- package/dist/network/url-match.d.ts +8 -0
- package/dist/network/url-match.js +38 -0
- package/dist/recorder/apply.d.ts +3 -0
- package/dist/recorder/apply.js +10 -0
- package/dist/recorder/capture.d.ts +18 -0
- package/dist/recorder/capture.js +198 -0
- package/dist/recorder/index.d.ts +3 -0
- package/dist/recorder/index.js +3 -0
- package/dist/recorder/normalise.d.ts +68 -0
- package/dist/recorder/normalise.js +104 -0
- package/dist/recorder/ranking.d.ts +9 -0
- package/dist/recorder/ranking.js +21 -0
- package/dist/recorder/recorder.d.ts +52 -0
- package/dist/recorder/recorder.js +143 -0
- package/dist/recorder/session.d.ts +49 -0
- package/dist/recorder/session.js +113 -0
- package/dist/runner/module-type.d.ts +6 -0
- package/dist/runner/module-type.js +29 -0
- package/dist/runner/page-logs-report.d.ts +40 -0
- package/dist/runner/page-logs-report.js +44 -0
- package/dist/runner/prepare-run.d.ts +14 -0
- package/dist/runner/prepare-run.js +20 -0
- package/dist/runner/project.d.ts +17 -0
- package/dist/runner/project.js +33 -0
- package/dist/runner/registry.d.ts +7 -0
- package/dist/runner/registry.js +40 -0
- package/dist/runner/reporter.d.ts +43 -0
- package/dist/runner/reporter.js +83 -0
- package/dist/runner/run.d.ts +27 -0
- package/dist/runner/run.js +34 -0
- package/dist/runner/test-error.d.ts +3 -0
- package/dist/runner/test-error.js +18 -0
- package/dist/runner/test-runner.d.ts +44 -0
- package/dist/runner/test-runner.js +205 -0
- package/dist/script/call-function.d.ts +34 -0
- package/dist/script/call-function.js +71 -0
- package/dist/script/element-handle.d.ts +10 -0
- package/{src/script/element-handle.ts → dist/script/element-handle.js} +4 -4
- package/dist/script/helpers.d.ts +28 -0
- package/dist/script/helpers.js +50 -0
- package/dist/script/preload.d.ts +31 -0
- package/dist/script/preload.js +71 -0
- package/dist/script/serialize.d.ts +29 -0
- package/dist/script/serialize.js +207 -0
- package/dist/steps/build.d.ts +5 -0
- package/dist/steps/build.js +38 -0
- package/dist/steps/edit.d.ts +30 -0
- package/dist/steps/edit.js +80 -0
- package/dist/steps/emit.d.ts +6 -0
- package/dist/steps/emit.js +73 -0
- package/dist/steps/index.d.ts +5 -0
- package/dist/steps/index.js +4 -0
- package/dist/steps/model.d.ts +103 -0
- package/dist/steps/model.js +1 -0
- package/dist/steps/parse.d.ts +3 -0
- package/dist/steps/parse.js +272 -0
- package/dist/transport/bidi-connection.d.ts +46 -0
- package/dist/transport/bidi-connection.js +176 -0
- package/dist/transport/bidi-error.d.ts +10 -0
- package/dist/transport/bidi-error.js +10 -0
- package/dist/transport/subscriptions.d.ts +36 -0
- package/dist/transport/subscriptions.js +81 -0
- package/{src → dist}/types/test.d.ts +10 -4
- package/dist/wait/wait-until.d.ts +20 -0
- package/dist/wait/wait-until.js +63 -0
- package/package.json +48 -7
- package/.claude/settings.local.json +0 -7
- package/.env.example +0 -3
- package/.github/actions/setup/action.yml +0 -16
- package/.github/workflows/ci.yml +0 -71
- package/.trunk/configs/.markdownlint.yaml +0 -2
- package/.trunk/configs/.yamllint.yaml +0 -7
- package/.trunk/configs/svgo.config.mjs +0 -14
- package/.trunk/trunk.yaml +0 -34
- package/docs/superpowers/bidi-roadmap.md +0 -60
- package/docs/superpowers/plans/2026-09-29-auto-wait.md +0 -1827
- package/docs/superpowers/plans/2026-09-29-expect.md +0 -1350
- package/docs/superpowers/plans/2026-10-01-ci.md +0 -350
- package/docs/superpowers/plans/2026-10-01-test-api-alignment.md +0 -1821
- package/docs/superpowers/recorder-roadmap.md +0 -52
- package/docs/superpowers/specs/2026-09-29-auto-wait-design.md +0 -185
- package/docs/superpowers/specs/2026-09-29-bidi-foundation-design.md +0 -130
- package/docs/superpowers/specs/2026-09-29-contexts-and-storage-design.md +0 -88
- package/docs/superpowers/specs/2026-09-29-downloads-and-file-dialogs-design.md +0 -94
- package/docs/superpowers/specs/2026-09-29-emulation-design.md +0 -88
- package/docs/superpowers/specs/2026-09-29-expect-design.md +0 -130
- package/docs/superpowers/specs/2026-09-29-locate-nodes-design.md +0 -90
- package/docs/superpowers/specs/2026-09-29-logs-and-errors-design.md +0 -87
- package/docs/superpowers/specs/2026-09-29-navigation-waits-design.md +0 -83
- package/docs/superpowers/specs/2026-09-29-network-data-design.md +0 -78
- package/docs/superpowers/specs/2026-09-29-network-interception-design.md +0 -91
- package/docs/superpowers/specs/2026-09-29-network-tracking-design.md +0 -86
- package/docs/superpowers/specs/2026-09-29-page-api-design.md +0 -90
- package/docs/superpowers/specs/2026-09-29-preload-scripts-design.md +0 -82
- package/docs/superpowers/specs/2026-09-29-script-call-function-design.md +0 -107
- package/docs/superpowers/specs/2026-09-29-set-files-design.md +0 -62
- package/docs/superpowers/specs/2026-09-29-user-prompts-design.md +0 -75
- package/docs/superpowers/specs/2026-10-01-ci-design.md +0 -106
- package/docs/superpowers/specs/2026-10-01-test-api-alignment-design.md +0 -241
- package/public/logo-dark.svg +0 -236
- package/public/logo-light.svg +0 -262
- package/samurai.config.ts +0 -7
- package/src/assert/assertion-error.test.ts +0 -55
- package/src/assert/assertion-error.ts +0 -62
- package/src/assert/expect-locator.test.ts +0 -217
- package/src/assert/expect.test.ts +0 -73
- package/src/assert/expect.ts +0 -299
- package/src/browser/browser-context.browser-test.ts +0 -201
- package/src/browser/browser-context.test.ts +0 -407
- package/src/browser/browser-context.ts +0 -208
- package/src/browser/browser-finder.ts +0 -110
- package/src/browser/browser.test.ts +0 -88
- package/src/browser/browser.ts +0 -515
- package/src/browser/context-tree.test.ts +0 -86
- package/src/browser/context-tree.ts +0 -70
- package/src/browser/dialog.browser-test.ts +0 -144
- package/src/browser/dialog.test.ts +0 -322
- package/src/browser/dialog.ts +0 -83
- package/src/browser/download.test.ts +0 -161
- package/src/browser/download.ts +0 -172
- package/src/browser/downloads-dir.test.ts +0 -75
- package/src/browser/downloads-dir.ts +0 -39
- package/src/browser/emulation.browser-test.ts +0 -186
- package/src/browser/emulation.test.ts +0 -200
- package/src/browser/emulation.ts +0 -204
- package/src/browser/file-chooser.test.ts +0 -142
- package/src/browser/file-chooser.ts +0 -99
- package/src/browser/file-paths.ts +0 -18
- package/src/browser/goto.browser-test.ts +0 -44
- package/src/browser/navigation-error.ts +0 -26
- package/src/browser/navigation.browser-test.ts +0 -172
- package/src/browser/page-api.browser-test.ts +0 -228
- package/src/browser/page-logs.browser-test.ts +0 -119
- package/src/browser/page-logs.test.ts +0 -212
- package/src/browser/page-logs.ts +0 -208
- package/src/browser/page-wait.ts +0 -19
- package/src/browser/page.test.ts +0 -1567
- package/src/browser/page.ts +0 -1176
- package/src/browser/pdf.ts +0 -62
- package/src/browser/screenshot.ts +0 -65
- package/src/browser/transfers.browser-test.ts +0 -180
- package/src/config/config.ts +0 -33
- package/src/config/default.ts +0 -5
- package/src/config/fixtures.test.ts +0 -137
- package/src/config/mask.test.ts +0 -143
- package/src/config/mask.ts +0 -87
- package/src/config/run-settings.test.ts +0 -163
- package/src/config/run-settings.ts +0 -114
- package/src/config/secrets.ts +0 -70
- package/src/config/variables.ts +0 -31
- package/src/index.ts +0 -10
- package/src/locator/action-timeout-error.test.ts +0 -83
- package/src/locator/action-timeout-error.ts +0 -72
- package/src/locator/element-state.test.ts +0 -181
- package/src/locator/element-state.ts +0 -159
- package/src/locator/locate-nodes.browser-test.ts +0 -169
- package/src/locator/locator-actions.test.ts +0 -355
- package/src/locator/locator-chain.test.ts +0 -292
- package/src/locator/locator.browser-test.ts +0 -137
- package/src/locator/locator.test.ts +0 -179
- package/src/locator/locator.ts +0 -656
- package/src/locator/selector-errors.ts +0 -18
- package/src/locator/selector.test.ts +0 -124
- package/src/locator/selector.ts +0 -107
- package/src/locator/set-files.browser-test.ts +0 -141
- package/src/locator/set-files.test.ts +0 -191
- package/src/locator/text-locator.test.ts +0 -118
- package/src/logger/index.test.ts +0 -28
- package/src/logger/index.ts +0 -40
- package/src/network/data-collector.test.ts +0 -111
- package/src/network/data-collector.ts +0 -92
- package/src/network/network-data.browser-test.ts +0 -192
- package/src/network/network-tracker.browser-test.ts +0 -151
- package/src/network/network-tracker.test.ts +0 -307
- package/src/network/network-tracker.ts +0 -286
- package/src/network/network-wait.ts +0 -28
- package/src/network/response.test.ts +0 -93
- package/src/network/response.ts +0 -58
- package/src/network/router.browser-test.ts +0 -260
- package/src/network/router.test.ts +0 -528
- package/src/network/router.ts +0 -420
- package/src/network/url-match.test.ts +0 -69
- package/src/network/url-match.ts +0 -41
- package/src/runner/page-logs-report.test.ts +0 -144
- package/src/runner/page-logs-report.ts +0 -82
- package/src/runner/prepare-run.test.ts +0 -33
- package/src/runner/prepare-run.ts +0 -36
- package/src/runner/registry.test.ts +0 -59
- package/src/runner/registry.ts +0 -46
- package/src/runner/reporter.test.ts +0 -73
- package/src/runner/reporter.ts +0 -109
- package/src/runner/test-error.test.ts +0 -39
- package/src/runner/test-error.ts +0 -20
- package/src/runner/test-runner.ts +0 -184
- package/src/script/call-function.browser-test.ts +0 -112
- package/src/script/call-function.test.ts +0 -174
- package/src/script/call-function.ts +0 -113
- package/src/script/helpers.test.ts +0 -116
- package/src/script/helpers.ts +0 -68
- package/src/script/preload.browser-test.ts +0 -144
- package/src/script/preload.test.ts +0 -180
- package/src/script/preload.ts +0 -102
- package/src/script/serialize.test.ts +0 -182
- package/src/script/serialize.ts +0 -203
- package/src/testing/browser-fixture.ts +0 -18
- package/src/testing/fake-websocket.ts +0 -72
- package/src/testing/stub-connector.ts +0 -154
- package/src/tests/index.spec.ts +0 -30
- package/src/transport/bidi-connection.test.ts +0 -155
- package/src/transport/bidi-connection.ts +0 -256
- package/src/transport/bidi-error.ts +0 -23
- package/src/transport/foundation.browser-test.ts +0 -73
- package/src/transport/subscriptions.test.ts +0 -140
- package/src/transport/subscriptions.ts +0 -110
- package/src/types/bidi-commands.test-d.ts +0 -55
- package/src/wait/wait-until.test.ts +0 -117
- package/src/wait/wait-until.ts +0 -86
- package/tsconfig.json +0 -44
- /package/{src/api.ts → dist/api.d.ts} +0 -0
- /package/{src/locator/text-locator.ts → dist/locator/text-locator.js} +0 -0
- /package/{src → dist}/types/bidi-modules/browser.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/browsing-context.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/emulation.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/input.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/log.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/network.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/permissions.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/script.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/session.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/storage.d.ts +0 -0
- /package/{src → dist}/types/bidi-modules/web-extensions.d.ts +0 -0
- /package/{src → dist}/types/bidi-protocols/command.d.ts +0 -0
- /package/{src → dist}/types/bidi-protocols/error.d.ts +0 -0
- /package/{src → dist}/types/bidi-protocols/event.d.ts +0 -0
- /package/{src → dist}/types/bidi.d.ts +0 -0
- /package/{src → dist}/types/browser.d.ts +0 -0
- /package/{src → dist}/types/config.d.ts +0 -0
- /package/{src → dist}/types/env.d.ts +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { BiDiError } from "../transport/bidi-error.js";
|
|
2
|
+
import { applyEmulation } from "./emulation.js";
|
|
3
|
+
/**
|
|
4
|
+
* An isolated browsing session inside one browser: its own cookies, storage and cache. Pages opened in it
|
|
5
|
+
* share them; pages of other contexts see none of it.
|
|
6
|
+
*/
|
|
7
|
+
export class BrowserContext {
|
|
8
|
+
constructor(host,
|
|
9
|
+
/** The BiDi user context id; "default" for the browser's own */
|
|
10
|
+
id, isDefault) {
|
|
11
|
+
this.host = host;
|
|
12
|
+
this.id = id;
|
|
13
|
+
this.isDefault = isDefault;
|
|
14
|
+
this.opened = [];
|
|
15
|
+
this.isClosed = false;
|
|
16
|
+
}
|
|
17
|
+
/** True once `close()` has run */
|
|
18
|
+
get closed() {
|
|
19
|
+
return this.isClosed;
|
|
20
|
+
}
|
|
21
|
+
/** Opens a tab in this context */
|
|
22
|
+
async newPage() {
|
|
23
|
+
this.assertOpen();
|
|
24
|
+
return this.host.newPage({ type: "tab", ...(!this.isDefault && { userContext: this.id }) });
|
|
25
|
+
}
|
|
26
|
+
/** The pages opened in this context that are still open */
|
|
27
|
+
pages() {
|
|
28
|
+
this.opened = this.opened.filter((page) => !page.closed);
|
|
29
|
+
return [...this.opened];
|
|
30
|
+
}
|
|
31
|
+
/** @internal Called when a page is opened in this context */
|
|
32
|
+
register(page) {
|
|
33
|
+
this.opened.push(page);
|
|
34
|
+
page.setContext(this);
|
|
35
|
+
}
|
|
36
|
+
/** Adds cookies to this context's storage. Every cookie is checked before any is stored */
|
|
37
|
+
async addCookies(cookies) {
|
|
38
|
+
this.assertOpen();
|
|
39
|
+
const prepared = cookies.map(toBiDiCookie);
|
|
40
|
+
for (const cookie of prepared) {
|
|
41
|
+
await this.host.connector.send("storage.setCookie", { cookie, partition: this.partition() });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** The cookies of this context, optionally only those matching `filter` */
|
|
45
|
+
async cookies(filter) {
|
|
46
|
+
this.assertOpen();
|
|
47
|
+
const { cookies } = await this.host.connector.send("storage.getCookies", {
|
|
48
|
+
...(filter && { filter }),
|
|
49
|
+
partition: this.partition(),
|
|
50
|
+
});
|
|
51
|
+
return cookies.map(toCookie);
|
|
52
|
+
}
|
|
53
|
+
/** Deletes all cookies of this context, or those matching `filter` */
|
|
54
|
+
async clearCookies(filter) {
|
|
55
|
+
this.assertOpen();
|
|
56
|
+
await this.host.connector.send("storage.deleteCookies", {
|
|
57
|
+
...(filter && { filter }),
|
|
58
|
+
partition: this.partition(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Pretends things about every page of this context, including pages opened later: locale, timezone, user agent,
|
|
63
|
+
* geolocation, offline, orientation, screen size. A page's own `emulate()` wins over the context's.
|
|
64
|
+
* @example
|
|
65
|
+
* await context.emulate({ locale: "nl-NL", timezone: "Europe/Amsterdam", offline: false });
|
|
66
|
+
*/
|
|
67
|
+
async emulate(options) {
|
|
68
|
+
this.assertOpen();
|
|
69
|
+
await applyEmulation(this.host.connector, { userContexts: [this.id] }, options);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Grants, denies or resets a browser permission ("geolocation", "notifications", "camera", …) for `origin`
|
|
73
|
+
* in this context. Geolocation emulation only answers once the permission is granted.
|
|
74
|
+
*/
|
|
75
|
+
async setPermission(name, state, origin) {
|
|
76
|
+
this.assertOpen();
|
|
77
|
+
await this.host.connector.send("permissions.setPermission", {
|
|
78
|
+
descriptor: { name },
|
|
79
|
+
state,
|
|
80
|
+
origin,
|
|
81
|
+
...(!this.isDefault && { userContext: this.id }),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Removes the context; the browser closes its pages. The default context cannot be closed */
|
|
85
|
+
async close() {
|
|
86
|
+
if (this.isDefault)
|
|
87
|
+
throw new Error("cannot close the default context");
|
|
88
|
+
if (this.isClosed)
|
|
89
|
+
return;
|
|
90
|
+
try {
|
|
91
|
+
await this.host.connector.send("browser.removeUserContext", { userContext: this.id });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// Already gone: the goal is met
|
|
95
|
+
if (!(err instanceof BiDiError && err.code === "no such user context"))
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
this.isClosed = true;
|
|
99
|
+
const pages = this.opened;
|
|
100
|
+
this.opened = [];
|
|
101
|
+
await Promise.all(pages.map((page) => page.detach()));
|
|
102
|
+
this.host.forget(this);
|
|
103
|
+
}
|
|
104
|
+
partition() {
|
|
105
|
+
return { type: "storageKey", userContext: this.id };
|
|
106
|
+
}
|
|
107
|
+
assertOpen() {
|
|
108
|
+
if (this.isClosed)
|
|
109
|
+
throw new Error("context closed");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function toBiDiCookie(input) {
|
|
113
|
+
let { domain, path, secure } = input;
|
|
114
|
+
if (input.url !== undefined) {
|
|
115
|
+
const url = new URL(input.url);
|
|
116
|
+
domain ??= url.hostname;
|
|
117
|
+
path ??= url.pathname;
|
|
118
|
+
secure ??= url.protocol === "https:";
|
|
119
|
+
}
|
|
120
|
+
if (domain === undefined)
|
|
121
|
+
throw new TypeError(`cookie "${input.name}" needs a domain or a url`);
|
|
122
|
+
return {
|
|
123
|
+
name: input.name,
|
|
124
|
+
value: { type: "string", value: input.value },
|
|
125
|
+
domain,
|
|
126
|
+
path: path ?? "/",
|
|
127
|
+
...(secure !== undefined && { secure }),
|
|
128
|
+
...(input.httpOnly !== undefined && { httpOnly: input.httpOnly }),
|
|
129
|
+
...(input.sameSite !== undefined && { sameSite: input.sameSite }),
|
|
130
|
+
...(input.expiry !== undefined && { expiry: input.expiry }),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function toCookie(cookie) {
|
|
134
|
+
return {
|
|
135
|
+
name: cookie.name,
|
|
136
|
+
value: cookie.value.type === "base64"
|
|
137
|
+
? Buffer.from(cookie.value.value, "base64").toString("utf8")
|
|
138
|
+
: cookie.value.value,
|
|
139
|
+
domain: cookie.domain,
|
|
140
|
+
path: cookie.path,
|
|
141
|
+
httpOnly: cookie.httpOnly,
|
|
142
|
+
secure: cookie.secure,
|
|
143
|
+
sameSite: cookie.sameSite,
|
|
144
|
+
...(cookie.expiry !== undefined && { expiry: cookie.expiry }),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import logger from "../logger/index.js";
|
|
5
|
+
const supportedBrowsers = ["firefox"];
|
|
6
|
+
const macBrowserPaths = {
|
|
7
|
+
// chrome: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
8
|
+
firefox: "/Applications/Firefox.app/Contents/MacOS/Firefox",
|
|
9
|
+
};
|
|
10
|
+
export function findBrowser(browserName) {
|
|
11
|
+
logger.verbose("Checking install location for %s", browserName);
|
|
12
|
+
if (!supportedBrowsers.includes(browserName)) {
|
|
13
|
+
throw new Error("This browser is not supported. Supported browsers include: " +
|
|
14
|
+
supportedBrowsers.join(", "));
|
|
15
|
+
}
|
|
16
|
+
let browserLocation = "";
|
|
17
|
+
const notFoundMsg = `Cannot find browser ${browserName} on this machine! Is it installed?`;
|
|
18
|
+
try {
|
|
19
|
+
browserLocation = tryFindBrowser(browserName);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new Error(notFoundMsg);
|
|
23
|
+
}
|
|
24
|
+
assert(browserLocation, notFoundMsg);
|
|
25
|
+
logger.verbose("Browser found at: %s", browserLocation);
|
|
26
|
+
return browserLocation;
|
|
27
|
+
}
|
|
28
|
+
function tryFindBrowser(browserName) {
|
|
29
|
+
logger.debug("Current platform: %s", process.platform);
|
|
30
|
+
switch (process.platform) {
|
|
31
|
+
case "win32":
|
|
32
|
+
return findBrowserWindows(browserName);
|
|
33
|
+
case "darwin":
|
|
34
|
+
return findBrowserMac(browserName);
|
|
35
|
+
case "linux":
|
|
36
|
+
return findBrowserLinux(browserName);
|
|
37
|
+
default:
|
|
38
|
+
throw new Error("This platform is not supported");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function findBrowserWindows(browserName) {
|
|
42
|
+
// Function to prevent search the entire file system
|
|
43
|
+
// We'll only try the most common paths
|
|
44
|
+
const possibleDirs = ["Program\ Files", "Program\ Files (x86)"];
|
|
45
|
+
const where = (dirPath) => {
|
|
46
|
+
const command = `where /r ${dirPath} ${browserName}.exe`;
|
|
47
|
+
try {
|
|
48
|
+
logger.verbose("Running command: %s", command);
|
|
49
|
+
const whereResults = execSync(command, {
|
|
50
|
+
encoding: "utf8",
|
|
51
|
+
});
|
|
52
|
+
logger.debug("Command results: \n", whereResults);
|
|
53
|
+
const results = whereResults.split(/\n/g);
|
|
54
|
+
return results[0];
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logger.verbose("Error while executing %s", command, { error });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
let result = undefined;
|
|
61
|
+
for (const possibleDir of possibleDirs) {
|
|
62
|
+
logger.debug("Checking directory: %s", possibleDir);
|
|
63
|
+
result = where(possibleDir);
|
|
64
|
+
if (result)
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (!result) {
|
|
68
|
+
throw new Error("'where' yielded no results");
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
function findBrowserMac(browserName) {
|
|
73
|
+
const checkPathExists = (path) => {
|
|
74
|
+
logger.debug("Checking path: %s", path);
|
|
75
|
+
const exists = existsSync(path);
|
|
76
|
+
if (!exists) {
|
|
77
|
+
throw new Error(`Did not find ${browserName} at ${path}`);
|
|
78
|
+
}
|
|
79
|
+
return path;
|
|
80
|
+
};
|
|
81
|
+
return checkPathExists(macBrowserPaths[browserName]);
|
|
82
|
+
}
|
|
83
|
+
const linuxBinaryNames = {
|
|
84
|
+
// chrome: "google-chrome",
|
|
85
|
+
firefox: "firefox",
|
|
86
|
+
};
|
|
87
|
+
function findBrowserLinux(browserName) {
|
|
88
|
+
const command = `which ${linuxBinaryNames[browserName]}`;
|
|
89
|
+
logger.debug("Running command: %s", command);
|
|
90
|
+
const result = execSync(command, {
|
|
91
|
+
encoding: "utf8",
|
|
92
|
+
stdio: "pipe",
|
|
93
|
+
});
|
|
94
|
+
return result.replace(/\n/g, "");
|
|
95
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
2
|
+
import type { SupportedBrowser } from "../types/browser.js";
|
|
3
|
+
import { BiDiConnector } from "../transport/bidi-connection.js";
|
|
4
|
+
import Page from "./page.js";
|
|
5
|
+
import { BrowserContext } from "./browser-context.js";
|
|
6
|
+
import type { UserPromptHandler } from "../types/bidi-modules/session.js";
|
|
7
|
+
import { type EmulationOptions } from "./emulation.js";
|
|
8
|
+
import type { BiDiCommands } from "../types/bidi.js";
|
|
9
|
+
import type { CookieFilter, PartialCookie, PartitionDescriptor } from "../types/bidi-modules/storage.js";
|
|
10
|
+
/**
|
|
11
|
+
* Sent with session.new. With "ignore" the browser leaves a JavaScript dialog open and reports it
|
|
12
|
+
* (`browsingContext.userPromptOpened`), so the framework decides how to answer instead of the browser.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SESSION_CAPABILITIES: {
|
|
15
|
+
alwaysMatch: {
|
|
16
|
+
unhandledPromptBehavior: {
|
|
17
|
+
default: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare const browserLaunchFlag: (browserName: SupportedBrowser, launchOptions: Partial<BrowserLaunchOptions>) => string[];
|
|
22
|
+
/**
|
|
23
|
+
* Stops what a failed launch started. A browser left running holds the profile (the next launch
|
|
24
|
+
* fails with "already open") and keeps the test process alive.
|
|
25
|
+
*/
|
|
26
|
+
export declare function abandonLaunch(browserProc: {
|
|
27
|
+
kill(): boolean;
|
|
28
|
+
}, biDiConnector: {
|
|
29
|
+
kill(): void;
|
|
30
|
+
} | undefined): void;
|
|
31
|
+
export interface BrowserLaunchOptions {
|
|
32
|
+
/** Which port to use for the WebDeveloper tools */
|
|
33
|
+
port: number;
|
|
34
|
+
/** Firefox only */
|
|
35
|
+
profileDir: string;
|
|
36
|
+
/** Start the browser in headless mode or in UI mode */
|
|
37
|
+
headless: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Options of `browser.newContext()` */
|
|
40
|
+
export interface ContextOptions extends EmulationOptions {
|
|
41
|
+
acceptInsecureCerts?: boolean;
|
|
42
|
+
/** How this context's pages answer JavaScript dialogs; the session default is to leave them for the framework */
|
|
43
|
+
unhandledPromptBehavior?: UserPromptHandler;
|
|
44
|
+
}
|
|
45
|
+
export declare class Browser {
|
|
46
|
+
private browserProc;
|
|
47
|
+
private biDiConnector;
|
|
48
|
+
private userContexts;
|
|
49
|
+
private host;
|
|
50
|
+
/** The browser's own context, the one `Browser.launch`'s page lives in */
|
|
51
|
+
readonly defaultContext: BrowserContext;
|
|
52
|
+
/** Where downloads are saved; undefined when the browser could not be told (it then uses its own folder) */
|
|
53
|
+
readonly downloadsDir: string | undefined;
|
|
54
|
+
private exitedPromise;
|
|
55
|
+
constructor({ browserProc, biDiConnector, downloadsDir, }: {
|
|
56
|
+
browserProc: ChildProcessWithoutNullStreams;
|
|
57
|
+
biDiConnector: BiDiConnector;
|
|
58
|
+
downloadsDir?: string | undefined;
|
|
59
|
+
});
|
|
60
|
+
/** Resolves when the browser process has exited, whether `close()` or a person closed it */
|
|
61
|
+
get exited(): Promise<void>;
|
|
62
|
+
static launch(browserName: SupportedBrowser, launchOptions?: Partial<BrowserLaunchOptions>,
|
|
63
|
+
/** Aborting kills the browser process and rejects the launch */
|
|
64
|
+
signal?: AbortSignal): Promise<{
|
|
65
|
+
browser: Browser;
|
|
66
|
+
page: Page;
|
|
67
|
+
}>;
|
|
68
|
+
/** Closes the browser via BiDi browser.close, then makes sure the process has exited */
|
|
69
|
+
close(): Promise<void>;
|
|
70
|
+
/** Alias of close() */
|
|
71
|
+
kill(): Promise<void>;
|
|
72
|
+
newPage({ type, background, userContext, }: BiDiCommands["browsingContext.create"]["params"]): Promise<Page>;
|
|
73
|
+
/**
|
|
74
|
+
* Creates an isolated context: its own cookies, storage and cache. `browser.close()` removes the contexts
|
|
75
|
+
* that are still open, as Firefox would otherwise keep them in its profile.
|
|
76
|
+
* @example
|
|
77
|
+
* const alice = await browser.newContext();
|
|
78
|
+
* const page = await alice.newPage();
|
|
79
|
+
*/
|
|
80
|
+
newContext(options?: ContextOptions): Promise<BrowserContext>;
|
|
81
|
+
/** The default context, then the contexts this browser created that are still open */
|
|
82
|
+
contexts(): BrowserContext[];
|
|
83
|
+
private contextFor;
|
|
84
|
+
/** A user context this browser did not create (Firefox keeps them in its profile): usable, never closed by `close()` */
|
|
85
|
+
private adopt;
|
|
86
|
+
getCookie(filter: CookieFilter, partition: PartitionDescriptor): Promise<{
|
|
87
|
+
cookies: import("../types/bidi-modules/network.js").Cookie[];
|
|
88
|
+
partitionKey: import("../types/bidi-modules/storage.js").PartitionKey;
|
|
89
|
+
}>;
|
|
90
|
+
setCookie(cookie: PartialCookie, partition?: PartitionDescriptor): Promise<{
|
|
91
|
+
partitionKey: import("../types/bidi-modules/storage.js").PartitionKey;
|
|
92
|
+
}>;
|
|
93
|
+
}
|
|
94
|
+
/** Writes the browser's user.js unless it already holds the current prefs; an outdated one is replaced */
|
|
95
|
+
export declare function ensureBrowserProfile(browserName: SupportedBrowser, profilePath?: string | undefined): void;
|