@itmetsam/samurai-framework 0.21.5 → 0.22.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/dist/api.d.ts +8 -3
- package/dist/api.js +1 -0
- package/dist/browser/browser-context.d.ts +18 -6
- package/dist/browser/browser-context.js +25 -7
- package/dist/browser/browser.d.ts +4 -4
- package/dist/browser/browser.js +11 -8
- package/dist/browser/chrome-launch.js +9 -1
- package/dist/browser/context-cookie-store.d.ts +17 -0
- package/dist/browser/context-cookie-store.js +90 -0
- package/dist/browser/index.d.ts +3 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/keyboard.d.ts +35 -0
- package/dist/browser/keyboard.js +83 -0
- package/dist/browser/mouse.d.ts +42 -0
- package/dist/browser/mouse.js +66 -0
- package/dist/browser/page-content.d.ts +4 -0
- package/dist/browser/page-content.js +12 -0
- package/dist/browser/page-events.d.ts +11 -0
- package/dist/browser/page-events.js +23 -0
- package/dist/browser/page-logging.d.ts +24 -0
- package/dist/browser/page-logging.js +43 -0
- package/dist/browser/page-navigation.d.ts +0 -2
- package/dist/browser/page-navigation.js +1 -6
- package/dist/browser/page-settings.d.ts +1 -1
- package/dist/browser/page-viewport.d.ts +21 -0
- package/dist/browser/page-viewport.js +33 -0
- package/dist/browser/page.d.ts +23 -16
- package/dist/browser/page.js +48 -71
- package/dist/browser/screenshot.d.ts +6 -0
- package/dist/browser/screenshot.js +14 -0
- package/dist/browser/storage-state.d.ts +0 -2
- package/dist/browser/storage-state.js +0 -20
- package/dist/browser/use-applier.d.ts +16 -5
- package/dist/browser/use-applier.js +44 -17
- package/dist/browser/use-commands.d.ts +36 -0
- package/dist/browser/use-commands.js +120 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +8 -5
- package/dist/cli/console-reporter.js +5 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +4 -1
- package/dist/config/base-url.d.ts +4 -0
- package/dist/config/base-url.js +6 -0
- package/dist/config/config.js +7 -0
- package/dist/config/fixture-use.d.ts +19 -0
- package/dist/config/fixture-use.js +44 -0
- package/dist/config/fully-parallel.d.ts +3 -0
- package/dist/config/fully-parallel.js +6 -0
- package/dist/config/group-use.d.ts +10 -0
- package/dist/config/group-use.js +51 -0
- package/dist/config/resolved-config.d.ts +2 -0
- package/dist/config/resolved-config.js +3 -0
- package/dist/config/storage-state-file.d.ts +3 -0
- package/dist/config/storage-state-file.js +20 -0
- package/dist/config/use-options.d.ts +3 -1
- package/dist/config/use-options.js +74 -14
- package/dist/config/web-server-options.d.ts +7 -0
- package/dist/config/web-server-options.js +111 -0
- package/dist/locator/check-actions.js +1 -1
- package/dist/locator/drag-actions.d.ts +17 -0
- package/dist/locator/drag-actions.js +80 -0
- package/dist/locator/element-actions.d.ts +10 -4
- package/dist/locator/element-actions.js +23 -16
- package/dist/locator/element-state.d.ts +5 -0
- package/dist/locator/element-state.js +2 -1
- package/dist/locator/event-actions.d.ts +10 -0
- package/dist/locator/event-actions.js +81 -0
- package/dist/locator/input-actions.d.ts +2 -11
- package/dist/locator/input-actions.js +3 -56
- package/dist/locator/key-actions.d.ts +11 -0
- package/dist/locator/key-actions.js +52 -0
- package/dist/locator/key-map.d.ts +16 -0
- package/dist/locator/key-map.js +76 -0
- package/dist/locator/locator.d.ts +35 -5
- package/dist/locator/locator.js +70 -16
- package/dist/locator/page-scripts.d.ts +2 -0
- package/dist/locator/page-scripts.js +7 -0
- package/dist/locator/pointer-actions.d.ts +44 -0
- package/dist/locator/pointer-actions.js +117 -0
- package/dist/locator/pointer-element-actions.d.ts +21 -0
- package/dist/locator/pointer-element-actions.js +42 -0
- package/dist/request/api-request-context.d.ts +65 -0
- package/dist/request/api-request-context.js +198 -0
- package/dist/request/api-response.d.ts +34 -0
- package/dist/request/api-response.js +57 -0
- package/dist/request/cookie-jar.d.ts +48 -0
- package/dist/request/cookie-jar.js +164 -0
- package/dist/request/http-transport.d.ts +31 -0
- package/dist/request/http-transport.js +113 -0
- package/dist/request/redirect.d.ts +10 -0
- package/dist/request/redirect.js +21 -0
- package/dist/request/request-body.d.ts +27 -0
- package/dist/request/request-body.js +71 -0
- package/dist/request/request.d.ts +16 -0
- package/dist/request/request.js +20 -0
- package/dist/runner/all-hooks.d.ts +7 -1
- package/dist/runner/all-hooks.js +17 -1
- package/dist/runner/fixture-defs.d.ts +2 -1
- package/dist/runner/fixture-defs.js +52 -18
- package/dist/runner/fixture-meta.d.ts +20 -0
- package/dist/runner/fixture-meta.js +109 -0
- package/dist/runner/fixture-options.d.ts +8 -0
- package/dist/runner/fixture-options.js +35 -0
- package/dist/runner/fixture-outputs.d.ts +11 -0
- package/dist/runner/fixture-outputs.js +28 -0
- package/dist/runner/fixture-registry.d.ts +35 -0
- package/dist/runner/fixture-registry.js +73 -0
- package/dist/runner/fixture-scope.d.ts +39 -9
- package/dist/runner/fixture-scope.js +139 -70
- package/dist/runner/fixture-start.d.ts +27 -0
- package/dist/runner/fixture-start.js +76 -0
- package/dist/runner/fixture-use.d.ts +23 -0
- package/dist/runner/fixture-use.js +64 -0
- package/dist/runner/fixture-worker.d.ts +26 -0
- package/dist/runner/fixture-worker.js +46 -0
- package/dist/runner/fixtures.d.ts +4 -1
- package/dist/runner/fixtures.js +3 -2
- package/dist/runner/global-hooks.d.ts +13 -0
- package/dist/runner/global-hooks.js +66 -0
- package/dist/runner/options.d.ts +13 -2
- package/dist/runner/output-tail.d.ts +14 -0
- package/dist/runner/output-tail.js +30 -0
- package/dist/runner/pool-schedule.d.ts +22 -0
- package/dist/runner/pool-schedule.js +55 -0
- package/dist/runner/pool-units.d.ts +34 -0
- package/dist/runner/pool-units.js +85 -0
- package/dist/runner/pooled-run.d.ts +7 -5
- package/dist/runner/pooled-run.js +19 -9
- package/dist/runner/prepare-run.js +5 -0
- package/dist/runner/registry.js +21 -7
- package/dist/runner/reporter.d.ts +13 -1
- package/dist/runner/reporter.js +13 -2
- package/dist/runner/request-fixture.d.ts +14 -0
- package/dist/runner/request-fixture.js +25 -0
- package/dist/runner/run-hooks.d.ts +16 -0
- package/dist/runner/run-hooks.js +52 -0
- package/dist/runner/run-test.d.ts +3 -0
- package/dist/runner/run-test.js +23 -3
- package/dist/runner/run.d.ts +8 -0
- package/dist/runner/run.js +10 -0
- package/dist/runner/select.d.ts +15 -4
- package/dist/runner/select.js +38 -12
- package/dist/runner/serial-run.d.ts +23 -0
- package/dist/runner/serial-run.js +88 -0
- package/dist/runner/serial.d.ts +34 -0
- package/dist/runner/serial.js +63 -0
- package/dist/runner/shard.d.ts +22 -0
- package/dist/runner/shard.js +73 -0
- package/dist/runner/suite.d.ts +3 -3
- package/dist/runner/suite.js +4 -3
- package/dist/runner/test-function.d.ts +15 -3
- package/dist/runner/test-info.js +2 -1
- package/dist/runner/test-runner.d.ts +1 -0
- package/dist/runner/test-runner.js +67 -18
- package/dist/runner/use-options.d.ts +18 -4
- package/dist/runner/use-options.js +33 -6
- package/dist/runner/wait-for-url.d.ts +20 -0
- package/dist/runner/wait-for-url.js +65 -0
- package/dist/runner/web-server.d.ts +16 -0
- package/dist/runner/web-server.js +165 -0
- package/dist/runner/worker-pool.d.ts +13 -5
- package/dist/runner/worker-pool.js +85 -51
- package/dist/runner/worker-protocol.d.ts +8 -0
- package/dist/runner/worker-session.js +9 -1
- package/dist/runner/worker.d.ts +2 -0
- package/dist/runner/worker.js +7 -1
- package/dist/types/config.d.ts +117 -21
- package/dist/types/extend.d.ts +54 -2
- package/dist/types/test.d.ts +42 -0
- package/dist/types/use.d.ts +59 -7
- package/package.json +1 -1
- package/dist/browser/emulation.d.ts +0 -61
- package/dist/browser/emulation.js +0 -180
package/dist/api.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
export { test, describe, beforeEach, afterEach, beforeAll, afterAll, } from "./runner/registry.js";
|
|
2
|
+
export { request, type NewRequestContextOptions } from "./request/request.js";
|
|
3
|
+
export type { APIRequestContext, RequestOptions, } from "./request/api-request-context.js";
|
|
4
|
+
export type { APIResponse } from "./request/api-response.js";
|
|
5
|
+
export type { FilePayload } from "./request/request-body.js";
|
|
2
6
|
export { expect } from "./assert/expect.js";
|
|
3
7
|
export { defineConfig } from "./config/config.js";
|
|
8
|
+
export type { GlobalHookConfig, WebServerConfig } from "./types/config.js";
|
|
4
9
|
export { defineStep, type StepDefinition, type StepResult, type StepRunInput, } from "./flows/steps/index.js";
|
|
5
|
-
export type { AllHookFixtures, TestAnnotation, TestAttachment, TestDetails, TestFixtures, TestInfo, TestOptions, TestOutputs, TestStepEntry, } from "./types/test.js";
|
|
6
|
-
export type { FixtureOptions } from "./types/extend.js";
|
|
7
|
-
export type { ColorScheme, StorageState, StorageStateCookie, UseOptions, } from "./types/use.js";
|
|
10
|
+
export type { AllHookFixtures, TestAnnotation, TestAttachment, TestDetails, TestFixtures, TestInfo, TestOptions, TestOutputs, TestFixtureEntry, TestStepEntry, } from "./types/test.js";
|
|
11
|
+
export type { FixtureField, FixtureOptions, FixtureOutput, } from "./types/extend.js";
|
|
12
|
+
export type { ColorScheme, StorageState, StorageStateCookie, RuntimeUseOptions, UseOptions, FixtureUse, } from "./types/use.js";
|
|
8
13
|
export { generatedFile, type GeneratedFile, type FileInput, } from "./browser/generated-files.js";
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { test, describe, beforeEach, afterEach, beforeAll, afterAll, } from "./runner/registry.js";
|
|
2
|
+
export { request } from "./request/request.js";
|
|
2
3
|
export { expect } from "./assert/expect.js";
|
|
3
4
|
export { defineConfig } from "./config/config.js";
|
|
4
5
|
export { defineStep, } from "./flows/steps/index.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BiDiConnector } from "../transport/bidi-connection.js";
|
|
2
2
|
import type { SameSite } from "../types/bidi-modules/network.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { APIRequestContext, type RequestContextOptions } from "../request/api-request-context.js";
|
|
4
|
+
import type { RuntimeUseOptions } from "../types/use.js";
|
|
4
5
|
import type Page from "./page.js";
|
|
5
6
|
/** A cookie as `context.cookies()` returns it */
|
|
6
7
|
export interface Cookie {
|
|
@@ -54,6 +55,8 @@ export declare class BrowserContext {
|
|
|
54
55
|
readonly isDefault: boolean;
|
|
55
56
|
private opened;
|
|
56
57
|
private isClosed;
|
|
58
|
+
private requestContext;
|
|
59
|
+
private readonly requestDefaults;
|
|
57
60
|
constructor(host: ContextHost,
|
|
58
61
|
/** The BiDi user context id; "default" for the browser's own */
|
|
59
62
|
id: string, isDefault: boolean);
|
|
@@ -65,6 +68,14 @@ export declare class BrowserContext {
|
|
|
65
68
|
pages(): Page[];
|
|
66
69
|
/** @internal Called when a page is opened in this context */
|
|
67
70
|
register(page: Page): void;
|
|
71
|
+
/**
|
|
72
|
+
* Makes HTTP requests from the test that share this context's cookies: they send the cookies the pages hold,
|
|
73
|
+
* and the cookies the responses set are in the pages' `document.cookie` afterwards. Its `extraHTTPHeaders`
|
|
74
|
+
* and `ignoreHTTPSErrors` follow the run's `use` options.
|
|
75
|
+
*/
|
|
76
|
+
get request(): APIRequestContext;
|
|
77
|
+
/** @internal What `request` starts from: the run's `use.extraHTTPHeaders` and `acceptInsecureCerts` */
|
|
78
|
+
setRequestDefaults(defaults: RequestContextOptions): void;
|
|
68
79
|
/** Adds cookies to this context's storage. Every cookie is checked before any is stored */
|
|
69
80
|
addCookies(cookies: CookieInput[]): Promise<void>;
|
|
70
81
|
/** The cookies of this context, optionally only those matching `filter` */
|
|
@@ -72,15 +83,16 @@ export declare class BrowserContext {
|
|
|
72
83
|
/** Deletes all cookies of this context, or those matching `filter` */
|
|
73
84
|
clearCookies(filter?: CookieFilter): Promise<void>;
|
|
74
85
|
/**
|
|
75
|
-
*
|
|
76
|
-
* geolocation, offline, orientation, screen
|
|
86
|
+
* Changes the `use` options that can change while the browser runs for every page of this context, including
|
|
87
|
+
* pages opened later: locale, timezone, user agent, geolocation, offline, orientation, screen, hasTouch,
|
|
88
|
+
* javaScriptEnabled. A page's own `use()` wins over the context's.
|
|
77
89
|
* @example
|
|
78
|
-
* await context.
|
|
90
|
+
* await context.use({ locale: "nl-NL", timezone: "Europe/Amsterdam", offline: false });
|
|
79
91
|
*/
|
|
80
|
-
|
|
92
|
+
use(options: RuntimeUseOptions): Promise<void>;
|
|
81
93
|
/**
|
|
82
94
|
* Grants, denies or resets a browser permission ("geolocation", "notifications", "camera", …) for `origin`
|
|
83
|
-
* in this context.
|
|
95
|
+
* in this context. A geolocation override only answers once the permission is granted.
|
|
84
96
|
*/
|
|
85
97
|
setPermission(name: string, state: "granted" | "denied" | "prompt", origin: string): Promise<void>;
|
|
86
98
|
/** Removes the context; the browser closes its pages. The default context cannot be closed */
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { BiDiError } from "../transport/bidi-error.js";
|
|
2
|
-
import {
|
|
2
|
+
import { APIRequestContext, } from "../request/api-request-context.js";
|
|
3
|
+
import { ContextCookieStore } from "./context-cookie-store.js";
|
|
4
|
+
import { applyUse } from "./use-commands.js";
|
|
3
5
|
/**
|
|
4
6
|
* An isolated browsing session inside one browser: its own cookies, storage and cache. Pages opened in it
|
|
5
7
|
* share them; pages of other contexts see none of it.
|
|
@@ -13,6 +15,7 @@ export class BrowserContext {
|
|
|
13
15
|
this.isDefault = isDefault;
|
|
14
16
|
this.opened = [];
|
|
15
17
|
this.isClosed = false;
|
|
18
|
+
this.requestDefaults = {};
|
|
16
19
|
}
|
|
17
20
|
/** True once `close()` has run */
|
|
18
21
|
get closed() {
|
|
@@ -36,6 +39,19 @@ export class BrowserContext {
|
|
|
36
39
|
this.opened.push(page);
|
|
37
40
|
page.setContext(this);
|
|
38
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Makes HTTP requests from the test that share this context's cookies: they send the cookies the pages hold,
|
|
44
|
+
* and the cookies the responses set are in the pages' `document.cookie` afterwards. Its `extraHTTPHeaders`
|
|
45
|
+
* and `ignoreHTTPSErrors` follow the run's `use` options.
|
|
46
|
+
*/
|
|
47
|
+
get request() {
|
|
48
|
+
this.assertOpen();
|
|
49
|
+
return (this.requestContext ??= new APIRequestContext(this.requestDefaults, new ContextCookieStore(this)));
|
|
50
|
+
}
|
|
51
|
+
/** @internal What `request` starts from: the run's `use.extraHTTPHeaders` and `acceptInsecureCerts` */
|
|
52
|
+
setRequestDefaults(defaults) {
|
|
53
|
+
Object.assign(this.requestDefaults, defaults);
|
|
54
|
+
}
|
|
39
55
|
/** Adds cookies to this context's storage. Every cookie is checked before any is stored */
|
|
40
56
|
async addCookies(cookies) {
|
|
41
57
|
this.assertOpen();
|
|
@@ -65,18 +81,19 @@ export class BrowserContext {
|
|
|
65
81
|
});
|
|
66
82
|
}
|
|
67
83
|
/**
|
|
68
|
-
*
|
|
69
|
-
* geolocation, offline, orientation, screen
|
|
84
|
+
* Changes the `use` options that can change while the browser runs for every page of this context, including
|
|
85
|
+
* pages opened later: locale, timezone, user agent, geolocation, offline, orientation, screen, hasTouch,
|
|
86
|
+
* javaScriptEnabled. A page's own `use()` wins over the context's.
|
|
70
87
|
* @example
|
|
71
|
-
* await context.
|
|
88
|
+
* await context.use({ locale: "nl-NL", timezone: "Europe/Amsterdam", offline: false });
|
|
72
89
|
*/
|
|
73
|
-
async
|
|
90
|
+
async use(options) {
|
|
74
91
|
this.assertOpen();
|
|
75
|
-
await
|
|
92
|
+
await applyUse(this.host.connector, { userContexts: [this.id] }, options);
|
|
76
93
|
}
|
|
77
94
|
/**
|
|
78
95
|
* Grants, denies or resets a browser permission ("geolocation", "notifications", "camera", …) for `origin`
|
|
79
|
-
* in this context.
|
|
96
|
+
* in this context. A geolocation override only answers once the permission is granted.
|
|
80
97
|
*/
|
|
81
98
|
async setPermission(name, state, origin) {
|
|
82
99
|
this.assertOpen();
|
|
@@ -104,6 +121,7 @@ export class BrowserContext {
|
|
|
104
121
|
throw err;
|
|
105
122
|
}
|
|
106
123
|
this.isClosed = true;
|
|
124
|
+
await this.requestContext?.dispose();
|
|
107
125
|
const pages = this.opened;
|
|
108
126
|
this.opened = [];
|
|
109
127
|
await Promise.all(pages.map((page) => page.detach()));
|
|
@@ -4,16 +4,16 @@ import Page from "./page.js";
|
|
|
4
4
|
import { type BrowserProcess } from "./chrome-launch.js";
|
|
5
5
|
import { BrowserContext } from "./browser-context.js";
|
|
6
6
|
import type { UserPromptHandler } from "../types/bidi-modules/session.js";
|
|
7
|
-
import {
|
|
7
|
+
import type { RuntimeUseOptions } from "../types/use.js";
|
|
8
8
|
import { UseApplier } from "./use-applier.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type { GroupUse } from "../types/config.js";
|
|
10
10
|
import { ChromeDownloadFolders } from "./download-folders.js";
|
|
11
11
|
import { type BrowserLaunchOptions } from "./launch-flags.js";
|
|
12
12
|
import type { BiDiCommands } from "../types/bidi.js";
|
|
13
13
|
import type { CookieFilter, PartialCookie, PartitionDescriptor } from "../types/bidi-modules/storage.js";
|
|
14
14
|
export type { BrowserLaunchOptions } from "./launch-flags.js";
|
|
15
15
|
/** Options of `browser.newContext()` */
|
|
16
|
-
export interface ContextOptions extends
|
|
16
|
+
export interface ContextOptions extends RuntimeUseOptions {
|
|
17
17
|
acceptInsecureCerts?: boolean;
|
|
18
18
|
/** How this context's pages answer JavaScript dialogs; the session default is to leave them for the framework */
|
|
19
19
|
unhandledPromptBehavior?: UserPromptHandler;
|
|
@@ -51,7 +51,7 @@ export declare class Browser {
|
|
|
51
51
|
* @internal The runner calls this after launch: the `use` options now apply to the default context and its pages,
|
|
52
52
|
* and to every context and page created later. Options passed to `newContext` win over them.
|
|
53
53
|
*/
|
|
54
|
-
setUse(options:
|
|
54
|
+
setUse(options: GroupUse, projectDir: string): Promise<UseApplier>;
|
|
55
55
|
/** Closes the browser via BiDi browser.close, then makes sure the process has exited */
|
|
56
56
|
close(): Promise<void>;
|
|
57
57
|
/** Alias of close() */
|
package/dist/browser/browser.js
CHANGED
|
@@ -5,7 +5,7 @@ import { projectBrowser } from "../browsers/resolve.js";
|
|
|
5
5
|
import Page from "./page.js";
|
|
6
6
|
import { launchChrome } from "./chrome-launch.js";
|
|
7
7
|
import { BrowserContext } from "./browser-context.js";
|
|
8
|
-
import {
|
|
8
|
+
import { validateRuntimeUse } from "./use-commands.js";
|
|
9
9
|
import { UseApplier } from "./use-applier.js";
|
|
10
10
|
import { prepareDownloadsDir, removeIfEmpty } from "./downloads-dir.js";
|
|
11
11
|
import { ChromeDownloadFolders } from "./download-folders.js";
|
|
@@ -189,31 +189,34 @@ export class Browser {
|
|
|
189
189
|
* const page = await alice.newPage();
|
|
190
190
|
*/
|
|
191
191
|
async newContext(options = {}) {
|
|
192
|
-
const { unhandledPromptBehavior, ...
|
|
192
|
+
const { unhandledPromptBehavior, ...settings } = options;
|
|
193
193
|
const insecure = options.acceptInsecureCerts ?? this.use?.acceptInsecureCerts;
|
|
194
|
-
delete
|
|
194
|
+
delete settings.acceptInsecureCerts;
|
|
195
195
|
// A wrong value must not leave a context behind, so it is refused before one is created
|
|
196
|
-
|
|
196
|
+
validateRuntimeUse(settings);
|
|
197
197
|
const { userContext } = await this.biDiConnector.send("browser.createUserContext", {
|
|
198
198
|
...(insecure !== undefined && { acceptInsecureCerts: insecure }),
|
|
199
199
|
...(unhandledPromptBehavior && { unhandledPromptBehavior }),
|
|
200
200
|
});
|
|
201
201
|
const context = new BrowserContext(this.host, userContext, false);
|
|
202
202
|
this.userContexts.set(userContext, context);
|
|
203
|
-
if (this.use || Object.keys(
|
|
203
|
+
if (this.use || Object.keys(settings).length > 0) {
|
|
204
204
|
try {
|
|
205
205
|
await this.use?.context(context);
|
|
206
|
-
if (Object.keys(
|
|
207
|
-
await context.
|
|
206
|
+
if (Object.keys(settings).length > 0)
|
|
207
|
+
await context.use(settings);
|
|
208
208
|
}
|
|
209
209
|
catch (err) {
|
|
210
210
|
// Firefox keeps a context in its profile until it is removed
|
|
211
|
-
await context.close().catch((closeErr) => logger.debug("Could not remove a context whose
|
|
211
|
+
await context.close().catch((closeErr) => logger.debug("Could not remove a context whose settings failed", {
|
|
212
212
|
closeErr,
|
|
213
213
|
}));
|
|
214
214
|
throw err;
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
|
+
// The option of this context wins over the run's `use.acceptInsecureCerts`
|
|
218
|
+
if (insecure !== undefined)
|
|
219
|
+
context.setRequestDefaults({ ignoreHTTPSErrors: insecure });
|
|
217
220
|
return context;
|
|
218
221
|
}
|
|
219
222
|
/** The default context, then the contexts this browser created that are still open */
|
|
@@ -118,18 +118,26 @@ export async function launchChrome(launch) {
|
|
|
118
118
|
launch.signal?.removeEventListener("abort", onAbort);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
/** How many of chromedriver's last lines the error carries when it exits before it is ready */
|
|
122
|
+
const OUTPUT_TAIL_LINES = 10;
|
|
121
123
|
function driverPort(driver) {
|
|
122
124
|
return new Promise((resolve, reject) => {
|
|
125
|
+
const tail = [];
|
|
123
126
|
const onData = (data) => {
|
|
124
127
|
logger.debug(`chromedriver: ${data}`);
|
|
125
128
|
const match = String(data).match(/started successfully on port (\d+)/);
|
|
126
129
|
if (match)
|
|
127
130
|
resolve(Number(match[1]));
|
|
131
|
+
for (const line of String(data).split("\n"))
|
|
132
|
+
if (line.trim() !== "")
|
|
133
|
+
tail.push(line);
|
|
134
|
+
tail.splice(0, Math.max(0, tail.length - OUTPUT_TAIL_LINES));
|
|
128
135
|
};
|
|
129
136
|
driver.stdout?.on("data", onData);
|
|
130
137
|
driver.stderr?.on("data", onData);
|
|
131
138
|
driver.once("error", reject);
|
|
132
|
-
driver.once("exit", (code) => reject(new Error(`chromedriver exited with code ${code} before it was ready`
|
|
139
|
+
driver.once("exit", (code, signal) => reject(new Error(`chromedriver exited with code ${code ?? signal} before it was ready` +
|
|
140
|
+
(tail.length > 0 ? `. Its last output:\n${tail.join("\n")}` : ""))));
|
|
133
141
|
});
|
|
134
142
|
}
|
|
135
143
|
/** chromedriver as the process of a Chrome launch: ending it ends Chrome, and so does deleting the session */
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CookieStore } from "../request/cookie-jar.js";
|
|
2
|
+
import type { StorageStateCookie } from "../types/use.js";
|
|
3
|
+
import type { BrowserContext } from "./browser-context.js";
|
|
4
|
+
/**
|
|
5
|
+
* The cookies of a browser context as a request context's cookie store: requests send what the pages of the
|
|
6
|
+
* context hold, and the `Set-Cookie` headers of the responses go into the context, so both see one session.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ContextCookieStore implements CookieStore {
|
|
9
|
+
private readonly context;
|
|
10
|
+
constructor(context: BrowserContext);
|
|
11
|
+
cookieHeader(url: URL): Promise<string | undefined>;
|
|
12
|
+
store(url: URL, setCookies: string[]): Promise<void>;
|
|
13
|
+
list(): Promise<StorageStateCookie[]>;
|
|
14
|
+
private add;
|
|
15
|
+
/** The site deleted the cookie: the browser keeps it under the host or, for a domain cookie, the dotted domain */
|
|
16
|
+
private remove;
|
|
17
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import logger from "../logger/index.js";
|
|
2
|
+
import { cookieHeaderOf, cookieMatches, isExpired, parseSetCookie, } from "../request/cookie-jar.js";
|
|
3
|
+
const CAPITAL = { strict: "Strict", lax: "Lax", none: "None" };
|
|
4
|
+
function stored(cookie) {
|
|
5
|
+
const sameSite = CAPITAL[cookie.sameSite];
|
|
6
|
+
return {
|
|
7
|
+
name: cookie.name,
|
|
8
|
+
value: cookie.value,
|
|
9
|
+
domain: cookie.domain.replace(/^\./, "").toLowerCase(),
|
|
10
|
+
hostOnly: !cookie.domain.startsWith("."),
|
|
11
|
+
path: cookie.path,
|
|
12
|
+
secure: cookie.secure,
|
|
13
|
+
httpOnly: cookie.httpOnly,
|
|
14
|
+
...(sameSite !== undefined && { sameSite }),
|
|
15
|
+
...(cookie.expiry !== undefined && { expires: cookie.expiry }),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The cookies of a browser context as a request context's cookie store: requests send what the pages of the
|
|
20
|
+
* context hold, and the `Set-Cookie` headers of the responses go into the context, so both see one session.
|
|
21
|
+
*/
|
|
22
|
+
export class ContextCookieStore {
|
|
23
|
+
constructor(context) {
|
|
24
|
+
this.context = context;
|
|
25
|
+
}
|
|
26
|
+
async cookieHeader(url) {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const matching = (await this.context.cookies())
|
|
29
|
+
.map(stored)
|
|
30
|
+
.filter((cookie) => cookieMatches(cookie, url, now));
|
|
31
|
+
return cookieHeaderOf(matching);
|
|
32
|
+
}
|
|
33
|
+
async store(url, setCookies) {
|
|
34
|
+
for (const header of setCookies) {
|
|
35
|
+
const cookie = parseSetCookie(header, url);
|
|
36
|
+
if (!cookie)
|
|
37
|
+
continue;
|
|
38
|
+
try {
|
|
39
|
+
if (isExpired(cookie))
|
|
40
|
+
await this.remove(cookie);
|
|
41
|
+
else
|
|
42
|
+
await this.add(cookie);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
// A browser refuses some cookies a server can send (Secure on a plain-http page, say): as a browser would
|
|
46
|
+
logger.debug("The browser did not take a Set-Cookie", {
|
|
47
|
+
name: cookie.name,
|
|
48
|
+
err,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async list() {
|
|
54
|
+
return (await this.context.cookies()).map((cookie) => ({
|
|
55
|
+
name: cookie.name,
|
|
56
|
+
value: cookie.value,
|
|
57
|
+
domain: cookie.domain,
|
|
58
|
+
path: cookie.path,
|
|
59
|
+
expires: cookie.expiry ?? -1,
|
|
60
|
+
httpOnly: cookie.httpOnly,
|
|
61
|
+
secure: cookie.secure,
|
|
62
|
+
sameSite: CAPITAL[cookie.sameSite] ?? "Lax",
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
add(cookie) {
|
|
66
|
+
return this.context.addCookies([
|
|
67
|
+
{
|
|
68
|
+
name: cookie.name,
|
|
69
|
+
value: cookie.value,
|
|
70
|
+
domain: cookie.hostOnly ? cookie.domain : `.${cookie.domain}`,
|
|
71
|
+
path: cookie.path,
|
|
72
|
+
secure: cookie.secure,
|
|
73
|
+
httpOnly: cookie.httpOnly,
|
|
74
|
+
...(cookie.sameSite !== undefined && {
|
|
75
|
+
sameSite: cookie.sameSite.toLowerCase(),
|
|
76
|
+
}),
|
|
77
|
+
...(cookie.expires !== undefined && { expiry: cookie.expires }),
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
/** The site deleted the cookie: the browser keeps it under the host or, for a domain cookie, the dotted domain */
|
|
82
|
+
async remove(cookie) {
|
|
83
|
+
for (const domain of [cookie.domain, `.${cookie.domain}`])
|
|
84
|
+
await this.context.clearCookies({
|
|
85
|
+
name: cookie.name,
|
|
86
|
+
domain,
|
|
87
|
+
path: cookie.path,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export { Browser, type BrowserLaunchOptions, type ContextOptions, } from "./browser.js";
|
|
2
2
|
export { BrowserContext } from "./browser-context.js";
|
|
3
3
|
export { default as Page } from "./page.js";
|
|
4
|
+
export type { default as Keyboard } from "./keyboard.js";
|
|
5
|
+
export type { default as Mouse } from "./mouse.js";
|
|
4
6
|
export { DownloadTimeoutError } from "./download.js";
|
|
5
7
|
export { UrlTimeoutError } from "./navigation-error.js";
|
|
6
8
|
export { ScriptError, ScriptSerializationError, type PageFunction, } from "../script/call-function.js";
|
|
7
9
|
export { ElementHandle } from "../script/element-handle.js";
|
|
8
10
|
export { RemoteObject } from "../script/serialize.js";
|
|
9
11
|
export type { BoundingBox } from "../locator/element-reads.js";
|
|
10
|
-
export {
|
|
12
|
+
export { UseError, UseUnsupportedError } from "./use-commands.js";
|
|
11
13
|
export { findBrowser } from "./browser-finder.js";
|
package/dist/browser/index.js
CHANGED
|
@@ -6,5 +6,5 @@ export { UrlTimeoutError } from "./navigation-error.js";
|
|
|
6
6
|
export { ScriptError, ScriptSerializationError, } from "../script/call-function.js";
|
|
7
7
|
export { ElementHandle } from "../script/element-handle.js";
|
|
8
8
|
export { RemoteObject } from "../script/serialize.js";
|
|
9
|
-
export {
|
|
9
|
+
export { UseError, UseUnsupportedError } from "./use-commands.js";
|
|
10
10
|
export { findBrowser } from "./browser-finder.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BiDiConnector } from "../transport/bidi-connection.js";
|
|
2
|
+
/**
|
|
3
|
+
* The page's keyboard: real key input to whatever has focus. BiDi remembers which keys are down between calls,
|
|
4
|
+
* so `down("Shift")`, other input, then `up("Shift")` works, and a held `Shift` capitalizes `press("a")`.
|
|
5
|
+
*/
|
|
6
|
+
export default class Keyboard {
|
|
7
|
+
private connector;
|
|
8
|
+
private contextId;
|
|
9
|
+
private assertOpen;
|
|
10
|
+
constructor(connector: BiDiConnector, contextId: string, assertOpen: () => void);
|
|
11
|
+
/**
|
|
12
|
+
* Presses and releases a key, or a chord: modifiers (`Control`, `Shift`, `Alt`, `Meta`, `ControlOrMeta`) joined to
|
|
13
|
+
* the key by `+`. Named keys are `Enter`, `Tab`, `Escape`, `Backspace`, `Delete`, `Space`, `Insert`, the arrows, `Home`, `End`,
|
|
14
|
+
* `PageUp`, `PageDown` and `F1` to `F12`; any other key is a single character. `delay` waits (ms) between press and release.
|
|
15
|
+
* @example
|
|
16
|
+
* await page.keyboard.press("Control+a");
|
|
17
|
+
* await page.keyboard.press("Shift+Tab");
|
|
18
|
+
*/
|
|
19
|
+
press(key: string, options?: {
|
|
20
|
+
delay?: number;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
/** Presses a key and keeps it down until `up`; a modifier stays in effect for the keys and clicks in between */
|
|
23
|
+
down(key: string): Promise<void>;
|
|
24
|
+
/** Releases a key pressed with `down`; a key that is not down is ignored */
|
|
25
|
+
up(key: string): Promise<void>;
|
|
26
|
+
/** Presses and releases one key per character of `text`, `delay` ms apart; a line break is Enter */
|
|
27
|
+
type(text: string, options?: {
|
|
28
|
+
delay?: number;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Inserts `text` at the caret of the focused element in one step, as a paste does: `input` fires, `keydown` and `keyup`
|
|
32
|
+
* do not. Does nothing when no editable element has focus.
|
|
33
|
+
*/
|
|
34
|
+
insertText(text: string): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { callFunction } from "../script/call-function.js";
|
|
2
|
+
import { chordSteps, performKeys, textSteps } from "../locator/key-actions.js";
|
|
3
|
+
import { parseKeyChord } from "../locator/key-map.js";
|
|
4
|
+
/** Types into whatever has focus, replacing the selection: an input, a textarea or an editable element, also in a same-origin frame */
|
|
5
|
+
const INSERT_TEXT = `(text) => {
|
|
6
|
+
let doc = document;
|
|
7
|
+
let el = doc.activeElement;
|
|
8
|
+
while (el && el.tagName === "IFRAME" && el.contentDocument && el.contentDocument.activeElement) {
|
|
9
|
+
doc = el.contentDocument;
|
|
10
|
+
el = doc.activeElement;
|
|
11
|
+
}
|
|
12
|
+
const selection = doc.getSelection();
|
|
13
|
+
// A freshly focused editable element can have no caret yet (Firefox): put it at the end
|
|
14
|
+
if (el && el.isContentEditable && selection && !el.contains(selection.anchorNode)) {
|
|
15
|
+
const range = doc.createRange();
|
|
16
|
+
range.selectNodeContents(el);
|
|
17
|
+
range.collapse(false);
|
|
18
|
+
selection.removeAllRanges();
|
|
19
|
+
selection.addRange(range);
|
|
20
|
+
}
|
|
21
|
+
doc.execCommand("insertText", false, text);
|
|
22
|
+
}`;
|
|
23
|
+
/** The key `down` and `up` take: one key, no chord, since a chord is several keys */
|
|
24
|
+
function singleKey(key, method) {
|
|
25
|
+
const chord = parseKeyChord(key, method);
|
|
26
|
+
if (chord.modifiers.length > 0) {
|
|
27
|
+
throw new Error(`${method}(): "${key}" is a chord. Press its keys one at a time`);
|
|
28
|
+
}
|
|
29
|
+
return chord.key;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The page's keyboard: real key input to whatever has focus. BiDi remembers which keys are down between calls,
|
|
33
|
+
* so `down("Shift")`, other input, then `up("Shift")` works, and a held `Shift` capitalizes `press("a")`.
|
|
34
|
+
*/
|
|
35
|
+
export default class Keyboard {
|
|
36
|
+
constructor(connector, contextId, assertOpen) {
|
|
37
|
+
this.connector = connector;
|
|
38
|
+
this.contextId = contextId;
|
|
39
|
+
this.assertOpen = assertOpen;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Presses and releases a key, or a chord: modifiers (`Control`, `Shift`, `Alt`, `Meta`, `ControlOrMeta`) joined to
|
|
43
|
+
* the key by `+`. Named keys are `Enter`, `Tab`, `Escape`, `Backspace`, `Delete`, `Space`, `Insert`, the arrows, `Home`, `End`,
|
|
44
|
+
* `PageUp`, `PageDown` and `F1` to `F12`; any other key is a single character. `delay` waits (ms) between press and release.
|
|
45
|
+
* @example
|
|
46
|
+
* await page.keyboard.press("Control+a");
|
|
47
|
+
* await page.keyboard.press("Shift+Tab");
|
|
48
|
+
*/
|
|
49
|
+
async press(key, options) {
|
|
50
|
+
this.assertOpen();
|
|
51
|
+
const chord = parseKeyChord(key, "keyboard.press");
|
|
52
|
+
await performKeys(this.connector, this.contextId, chordSteps(chord, options?.delay));
|
|
53
|
+
}
|
|
54
|
+
/** Presses a key and keeps it down until `up`; a modifier stays in effect for the keys and clicks in between */
|
|
55
|
+
async down(key) {
|
|
56
|
+
this.assertOpen();
|
|
57
|
+
await performKeys(this.connector, this.contextId, [
|
|
58
|
+
{ type: "keyDown", value: singleKey(key, "keyboard.down") },
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
/** Releases a key pressed with `down`; a key that is not down is ignored */
|
|
62
|
+
async up(key) {
|
|
63
|
+
this.assertOpen();
|
|
64
|
+
await performKeys(this.connector, this.contextId, [
|
|
65
|
+
{ type: "keyUp", value: singleKey(key, "keyboard.up") },
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
/** Presses and releases one key per character of `text`, `delay` ms apart; a line break is Enter */
|
|
69
|
+
async type(text, options) {
|
|
70
|
+
this.assertOpen();
|
|
71
|
+
await performKeys(this.connector, this.contextId, textSteps(text, options?.delay));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Inserts `text` at the caret of the focused element in one step, as a paste does: `input` fires, `keydown` and `keyup`
|
|
75
|
+
* do not. Does nothing when no editable element has focus.
|
|
76
|
+
*/
|
|
77
|
+
async insertText(text) {
|
|
78
|
+
this.assertOpen();
|
|
79
|
+
await callFunction(this.connector, this.contextId, INSERT_TEXT, [text], {
|
|
80
|
+
awaitPromise: false,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BiDiConnector } from "../transport/bidi-connection.js";
|
|
2
|
+
import { type MouseButton } from "../locator/pointer-actions.js";
|
|
3
|
+
/**
|
|
4
|
+
* The page's mouse: real pointer input at viewport coordinates (CSS pixels from the top left of the page's
|
|
5
|
+
* visible area). The pointer starts at 0, 0; `move` with `steps` runs from where the mouse last was through this object.
|
|
6
|
+
*/
|
|
7
|
+
export default class Mouse {
|
|
8
|
+
private connector;
|
|
9
|
+
private contextId;
|
|
10
|
+
private assertOpen;
|
|
11
|
+
private position;
|
|
12
|
+
constructor(connector: BiDiConnector, contextId: string, assertOpen: () => void);
|
|
13
|
+
/** Moves the pointer to `x`, `y` in a straight line of `steps` moves (default 1) */
|
|
14
|
+
move(x: number, y: number, options?: {
|
|
15
|
+
steps?: number;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
/** Presses a button (default left) where the pointer is, and keeps it down until `up` */
|
|
18
|
+
down(options?: {
|
|
19
|
+
button?: MouseButton;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
/** Releases a button pressed with `down` */
|
|
22
|
+
up(options?: {
|
|
23
|
+
button?: MouseButton;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Moves to `x`, `y` and clicks. `clickCount` presses in a row (2 is a double click), `delay` ms between each press and release.
|
|
27
|
+
* @example
|
|
28
|
+
* await page.mouse.click(120, 80, { button: "right" });
|
|
29
|
+
*/
|
|
30
|
+
click(x: number, y: number, options?: {
|
|
31
|
+
button?: MouseButton;
|
|
32
|
+
clickCount?: number;
|
|
33
|
+
delay?: number;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
/** `click` with two presses */
|
|
36
|
+
dblclick(x: number, y: number, options?: {
|
|
37
|
+
button?: MouseButton;
|
|
38
|
+
delay?: number;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
/** Turns the wheel where the pointer is by `deltaX` and `deltaY` pixels (positive is right and down) */
|
|
41
|
+
wheel(deltaX: number, deltaY: number): Promise<void>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { performPointer, wheelScroll, buttonCode, checkClick, clickSteps, moveSteps, } from "../locator/pointer-actions.js";
|
|
2
|
+
/** Throws `mouse.method(): ...` unless every value is a finite number */
|
|
3
|
+
function numbers(method, what, ...values) {
|
|
4
|
+
if (!values.every(Number.isFinite)) {
|
|
5
|
+
throw new Error(`mouse.${method}(): ${what} must be numbers`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The page's mouse: real pointer input at viewport coordinates (CSS pixels from the top left of the page's
|
|
10
|
+
* visible area). The pointer starts at 0, 0; `move` with `steps` runs from where the mouse last was through this object.
|
|
11
|
+
*/
|
|
12
|
+
export default class Mouse {
|
|
13
|
+
constructor(connector, contextId, assertOpen) {
|
|
14
|
+
this.connector = connector;
|
|
15
|
+
this.contextId = contextId;
|
|
16
|
+
this.assertOpen = assertOpen;
|
|
17
|
+
this.position = { x: 0, y: 0 };
|
|
18
|
+
}
|
|
19
|
+
/** Moves the pointer to `x`, `y` in a straight line of `steps` moves (default 1) */
|
|
20
|
+
async move(x, y, options) {
|
|
21
|
+
this.assertOpen();
|
|
22
|
+
numbers("move", "x and y", x, y);
|
|
23
|
+
const to = { x, y };
|
|
24
|
+
await performPointer(this.connector, this.contextId, moveSteps(this.position, to, options?.steps));
|
|
25
|
+
this.position = to;
|
|
26
|
+
}
|
|
27
|
+
/** Presses a button (default left) where the pointer is, and keeps it down until `up` */
|
|
28
|
+
async down(options) {
|
|
29
|
+
this.assertOpen();
|
|
30
|
+
await performPointer(this.connector, this.contextId, [
|
|
31
|
+
{
|
|
32
|
+
type: "pointerDown",
|
|
33
|
+
button: buttonCode(options?.button, "mouse.down"),
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
/** Releases a button pressed with `down` */
|
|
38
|
+
async up(options) {
|
|
39
|
+
this.assertOpen();
|
|
40
|
+
await performPointer(this.connector, this.contextId, [
|
|
41
|
+
{ type: "pointerUp", button: buttonCode(options?.button, "mouse.up") },
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Moves to `x`, `y` and clicks. `clickCount` presses in a row (2 is a double click), `delay` ms between each press and release.
|
|
46
|
+
* @example
|
|
47
|
+
* await page.mouse.click(120, 80, { button: "right" });
|
|
48
|
+
*/
|
|
49
|
+
async click(x, y, options) {
|
|
50
|
+
this.assertOpen();
|
|
51
|
+
numbers("click", "x and y", x, y);
|
|
52
|
+
checkClick(options ?? {}, "mouse.click");
|
|
53
|
+
await performPointer(this.connector, this.contextId, clickSteps({ x, y }, options, "mouse.click"));
|
|
54
|
+
this.position = { x, y };
|
|
55
|
+
}
|
|
56
|
+
/** `click` with two presses */
|
|
57
|
+
async dblclick(x, y, options) {
|
|
58
|
+
await this.click(x, y, { ...options, clickCount: 2 });
|
|
59
|
+
}
|
|
60
|
+
/** Turns the wheel where the pointer is by `deltaX` and `deltaY` pixels (positive is right and down) */
|
|
61
|
+
async wheel(deltaX, deltaY) {
|
|
62
|
+
this.assertOpen();
|
|
63
|
+
numbers("wheel", "deltaX and deltaY", deltaX, deltaY);
|
|
64
|
+
await wheelScroll(this.connector, this.contextId, this.position, deltaX, deltaY);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -3,3 +3,7 @@ import type { BiDiConnector } from "../transport/bidi-connection.js";
|
|
|
3
3
|
export declare function readContent(connector: BiDiConnector, context: string): Promise<string>;
|
|
4
4
|
/** Writes `html` as the page's document; true when the document reached `state` within `timeout` ms */
|
|
5
5
|
export declare function writeContent(connector: BiDiConnector, context: string, html: string, state: "load" | "domcontentloaded", timeout: number): Promise<boolean>;
|
|
6
|
+
/** The URL of the document now */
|
|
7
|
+
export declare function readUrl(connector: BiDiConnector, context: string): Promise<string>;
|
|
8
|
+
/** The title of the document now */
|
|
9
|
+
export declare function readTitle(connector: BiDiConnector, context: string): Promise<string>;
|
|
@@ -41,3 +41,15 @@ export function writeContent(connector, context, html, state, timeout) {
|
|
|
41
41
|
timeout,
|
|
42
42
|
]);
|
|
43
43
|
}
|
|
44
|
+
/** The URL of the document now */
|
|
45
|
+
export function readUrl(connector, context) {
|
|
46
|
+
return callFunction(connector, context, "() => location.href", [], {
|
|
47
|
+
awaitPromise: false,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** The title of the document now */
|
|
51
|
+
export function readTitle(connector, context) {
|
|
52
|
+
return callFunction(connector, context, "() => document.title", [], {
|
|
53
|
+
awaitPromise: false,
|
|
54
|
+
});
|
|
55
|
+
}
|