@allwright.dev/core 0.0.52 → 0.0.54
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 +5 -2
- package/dist/bootstrap.d.ts +0 -2
- package/dist/bootstrap.js +1 -97
- package/dist/browser.js +8 -5
- package/dist/index.d.ts +1 -1
- package/dist/mobile.js +169 -78
- package/dist/page.d.ts +3 -1
- package/dist/page.js +78 -27
- package/dist/runtime.d.ts +3 -3
- package/dist/runtime.js +41 -3
- package/dist/types.d.ts +117 -54
- package/package.json +3 -2
- package/proto/core/v1/context.proto +214 -0
- package/proto/core/v1/{browser.proto → surface.proto} +18 -13
- package/proto/engine/v1/engine.proto +4 -4
- package/proto/surfaces/mobile/v1/mobile.proto +56 -0
- package/proto/surfaces/web/v1/web.proto +2 -133
- package/proto/core/v1/tab.proto +0 -72
package/README.md
CHANGED
|
@@ -13,11 +13,14 @@ import { firefox } from "@allwright.dev/core";
|
|
|
13
13
|
|
|
14
14
|
const browser = await firefox.launch();
|
|
15
15
|
const page = browser.page();
|
|
16
|
-
await page.goto("https://
|
|
16
|
+
await page.goto("https://themoderninternet.vercel.app");
|
|
17
|
+
await page.click(
|
|
18
|
+
"xpath=//div[contains(@class,'card')][.//h2[normalize-space()='Form Inputs']]//button[normalize-space()='Visit page']",
|
|
19
|
+
);
|
|
17
20
|
await browser.close();
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Runnable examples live in [examples/web-basic.ts](./examples/web-basic.ts) and [examples/android-basic.ts](./examples/android-basic.ts).
|
|
21
24
|
|
|
22
25
|
Shared config files are stack-agnostic and can live in `allwright.config.yaml` or `allwright.config.json`.
|
|
23
26
|
The shared schema lives at the repo root in `allwright.schema.json`.
|
package/dist/bootstrap.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export declare function ensureRuntimeReady(serverAddr: string): Promise<string>;
|
|
2
2
|
export declare function shutdownManagedServer(): Promise<void>;
|
|
3
|
-
export declare function ensurePluginsInstalled(pluginIds: string[]): Promise<void>;
|
|
4
|
-
export declare function invokePlugin<TResponse>(pluginId: string, request: unknown): Promise<TResponse>;
|
package/dist/bootstrap.js
CHANGED
|
@@ -12,7 +12,7 @@ const ALLWRIGHT_HOME_ENV_VAR = "ALLWRIGHT_HOME";
|
|
|
12
12
|
const ALLWRIGHT_REPOSITORY_ENV_VAR = "ALLWRIGHT_REPOSITORY";
|
|
13
13
|
const ALLWRIGHT_VERSION_ENV_VAR = "ALLWRIGHT_VERSION";
|
|
14
14
|
const DEFAULT_RELEASE_REPOSITORY = "allwright-dev/allwright";
|
|
15
|
-
const DEFAULT_RELEASE_VERSION = "0.0.
|
|
15
|
+
const DEFAULT_RELEASE_VERSION = "0.0.54";
|
|
16
16
|
const STARTUP_TIMEOUT_MS = 20_000;
|
|
17
17
|
const PING_TIMEOUT_MS = 1_000;
|
|
18
18
|
const PROTO_ROOT = fileURLToPath(new URL("../proto/", import.meta.url));
|
|
@@ -168,65 +168,6 @@ async function installCli() {
|
|
|
168
168
|
fs.rmSync(assetPath, { force: true });
|
|
169
169
|
return cliPath;
|
|
170
170
|
}
|
|
171
|
-
export async function ensurePluginsInstalled(pluginIds) {
|
|
172
|
-
const expectedVersion = expectedRuntimeVersion();
|
|
173
|
-
const cliPath = await ensureCliAvailable(expectedVersion);
|
|
174
|
-
ensurePluginsInstalledWithCli(cliPath, expectedVersion, pluginIds);
|
|
175
|
-
}
|
|
176
|
-
export async function invokePlugin(pluginId, request) {
|
|
177
|
-
const expectedVersion = expectedRuntimeVersion();
|
|
178
|
-
const cliPath = await ensureCliAvailable(expectedVersion);
|
|
179
|
-
const requestJson = JSON.stringify(request);
|
|
180
|
-
const result = spawnSync(cliPath, ["plugin", "invoke", pluginId, "--request-json", requestJson], {
|
|
181
|
-
encoding: "utf8",
|
|
182
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
183
|
-
});
|
|
184
|
-
if (result.error) {
|
|
185
|
-
throw new Error(`failed to invoke allwright ${pluginId} plugin with ${cliPath}: ${result.error.message}`);
|
|
186
|
-
}
|
|
187
|
-
if (result.status !== 0) {
|
|
188
|
-
const details = [result.stdout, result.stderr]
|
|
189
|
-
.map((value) => value?.trim())
|
|
190
|
-
.filter((value) => !!value)
|
|
191
|
-
.join("\n");
|
|
192
|
-
throw new Error(details
|
|
193
|
-
? `allwright ${pluginId} plugin invocation failed:\n${details}`
|
|
194
|
-
: `allwright ${pluginId} plugin invocation failed`);
|
|
195
|
-
}
|
|
196
|
-
try {
|
|
197
|
-
return JSON.parse(result.stdout);
|
|
198
|
-
}
|
|
199
|
-
catch (error) {
|
|
200
|
-
throw new Error(`failed to decode allwright ${pluginId} plugin response: ${error instanceof Error ? error.message : String(error)}`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function ensurePluginsInstalledWithCli(cliPath, expectedVersion, pluginIds) {
|
|
204
|
-
for (const pluginId of new Set(pluginIds.map((value) => value.trim()).filter(Boolean))) {
|
|
205
|
-
const pluginPath = path.join(allwrightHome(), "plugins", pluginId, "lib", pluginLibraryFilename(pluginId));
|
|
206
|
-
if (isFile(pluginPath) && installedPluginVersion(pluginId) === expectedVersion) {
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
const result = spawnSync(cliPath, ["plugin", "install", pluginId, "--version", expectedVersion], {
|
|
210
|
-
encoding: "utf8",
|
|
211
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
212
|
-
});
|
|
213
|
-
if (result.error) {
|
|
214
|
-
throw new Error(`failed to install allwright ${pluginId} plugin with ${cliPath}: ${result.error.message}`);
|
|
215
|
-
}
|
|
216
|
-
if (result.status !== 0 || !isFile(pluginPath)) {
|
|
217
|
-
const details = [result.stdout, result.stderr]
|
|
218
|
-
.map((value) => value?.trim())
|
|
219
|
-
.filter((value) => !!value)
|
|
220
|
-
.join("\n");
|
|
221
|
-
throw new Error(details
|
|
222
|
-
? `allwright attempted to install the \`${pluginId}\` plugin automatically, but the install did not complete successfully:\n${details}`
|
|
223
|
-
: `allwright attempted to install the \`${pluginId}\` plugin automatically, but the install did not complete successfully`);
|
|
224
|
-
}
|
|
225
|
-
if (installedPluginVersion(pluginId) !== expectedVersion) {
|
|
226
|
-
throw new Error(`allwright attempted to install the \`${pluginId}\` plugin automatically, but version ${expectedVersion} is still not active`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
171
|
async function resolveReleaseTag() {
|
|
231
172
|
const version = process.env[ALLWRIGHT_VERSION_ENV_VAR]?.trim() || DEFAULT_RELEASE_VERSION;
|
|
232
173
|
if (version !== "latest") {
|
|
@@ -325,23 +266,6 @@ function isLocalServerAddr(serverAddr) {
|
|
|
325
266
|
const host = parseServerHost(serverAddr);
|
|
326
267
|
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
327
268
|
}
|
|
328
|
-
function installedPluginVersion(pluginId) {
|
|
329
|
-
const manifestPath = path.join(allwrightHome(), "plugins.txt");
|
|
330
|
-
if (!isFile(manifestPath)) {
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
for (const line of fs.readFileSync(manifestPath, "utf8").split(/\r?\n/)) {
|
|
334
|
-
const trimmed = line.trim();
|
|
335
|
-
if (!trimmed || trimmed.startsWith("#")) {
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
const [id, , version] = trimmed.split("\t", 3);
|
|
339
|
-
if (id === pluginId && version) {
|
|
340
|
-
return normalizeReleaseVersion(version);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return null;
|
|
344
|
-
}
|
|
345
269
|
async function allocateManagedServerAddr(serverAddr) {
|
|
346
270
|
const host = localBindingHost(serverAddr);
|
|
347
271
|
const port = await new Promise((resolve, reject) => {
|
|
@@ -454,26 +378,6 @@ function findExtractedCli(extractRoot) {
|
|
|
454
378
|
}
|
|
455
379
|
return null;
|
|
456
380
|
}
|
|
457
|
-
function pluginLibraryFilename(pluginId) {
|
|
458
|
-
const stem = pluginLibraryStem(pluginId);
|
|
459
|
-
if (process.platform === "darwin") {
|
|
460
|
-
return `lib${stem}.dylib`;
|
|
461
|
-
}
|
|
462
|
-
if (process.platform === "win32") {
|
|
463
|
-
return `${stem}.dll`;
|
|
464
|
-
}
|
|
465
|
-
return `lib${stem}.so`;
|
|
466
|
-
}
|
|
467
|
-
function pluginLibraryStem(pluginId) {
|
|
468
|
-
switch (pluginId) {
|
|
469
|
-
case "web":
|
|
470
|
-
return "allwright_surface_web";
|
|
471
|
-
case "mobile-android":
|
|
472
|
-
return "allwright_surface_mobile_android";
|
|
473
|
-
default:
|
|
474
|
-
throw new Error(`automatic install is not supported for allwright plugin \`${pluginId}\``);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
381
|
function autoInstallEnabled() {
|
|
478
382
|
const raw = process.env[ALLWRIGHT_AUTO_INSTALL_ENV_VAR]?.trim().toLowerCase();
|
|
479
383
|
return raw !== "0" && raw !== "false" && raw !== "no";
|
package/dist/browser.js
CHANGED
|
@@ -33,7 +33,7 @@ export class BrowserImpl {
|
|
|
33
33
|
this.launchNote = browserInfo.launchNote;
|
|
34
34
|
this.cdpWebSocketURL = browserInfo.cdpWebSocketURL;
|
|
35
35
|
this.userDataDir = browserInfo.userDataDir;
|
|
36
|
-
this.#initialPage = this.#createPage(state.launched.
|
|
36
|
+
this.#initialPage = this.#createPage(state.launched.initialPageSessionId ?? "");
|
|
37
37
|
}
|
|
38
38
|
sessionId;
|
|
39
39
|
browserName;
|
|
@@ -52,17 +52,17 @@ export class BrowserImpl {
|
|
|
52
52
|
async newPage(options = {}) {
|
|
53
53
|
this.#ensureOpen();
|
|
54
54
|
this.#stream.write({
|
|
55
|
-
|
|
55
|
+
openContext: {
|
|
56
56
|
retryOptions: options.timeoutMs ? { timeoutMs: options.timeoutMs } : undefined,
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
59
|
while (true) {
|
|
60
60
|
const event = await this.#queue.next();
|
|
61
|
-
if (event.
|
|
62
|
-
return this.#createPage(event.
|
|
61
|
+
if (event.contextOpened?.contextSessionId) {
|
|
62
|
+
return this.#createPage(event.contextOpened.contextSessionId);
|
|
63
63
|
}
|
|
64
64
|
if (event.error?.message) {
|
|
65
|
-
throw formatActionError("open
|
|
65
|
+
throw formatActionError("open page", event.error.message);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -77,6 +77,9 @@ export class BrowserImpl {
|
|
|
77
77
|
const event = await this.#queue.next();
|
|
78
78
|
if (event.closed) {
|
|
79
79
|
this.#closed = true;
|
|
80
|
+
for (const page of this.#pages.values()) {
|
|
81
|
+
page.dispose();
|
|
82
|
+
}
|
|
80
83
|
this.#stream.end();
|
|
81
84
|
return;
|
|
82
85
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { PageImpl } from "./page.js";
|
|
|
5
5
|
import { setServerAddr, shutdown } from "./runtime.js";
|
|
6
6
|
import type { Browser, BrowserKind, BrowserType, LaunchOptions, Page, ResolveConfigOptions, ResolvedAllwrightConfig } from "./types.js";
|
|
7
7
|
export { findConfigFile, loadConfigFile, resolveConfig, setServerAddr, shutdown };
|
|
8
|
-
export type { AllwrightConfig, Browser, BrowserInfo, BrowserKind, BrowserType, ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, LaunchOptions, MobileAndroidConnectOptions, MobileAndroidDevice, MobileAndroidLaunchOptions, MobileAndroidLocator,
|
|
8
|
+
export type { AllwrightConfig, Browser, BrowserInfo, BrowserKind, BrowserType, ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, LaunchOptions, MobileAndroidConnectOptions, MobileAndroidDevice, MobileAndroidLaunchOptions, MobileAndroidLocator, MobileAndroidApp, Locator, LocatorInfo, MobileSurfaceNamespace, NavigateResult, Page, PageInfo, PressOptions, PressResult, ResolveConfigOptions, ResolvedAllwrightConfig, RetryConfig, ScreenshotResult, TextResult, WaitForSelectorOptions, WaitForSelectorResult, } from "./types.js";
|
|
9
9
|
export declare const chromium: BrowserType;
|
|
10
10
|
export declare const firefox: BrowserType;
|
|
11
11
|
export { mobile };
|
package/dist/mobile.js
CHANGED
|
@@ -1,59 +1,117 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createBrowserSessionHandle, createPageHandle, getRuntime } from "./runtime.js";
|
|
2
2
|
import { chainMobileSelectorForTransport, normalizeMobileSelectorForTransport } from "./mobileSelectors.js";
|
|
3
|
-
function
|
|
4
|
-
return
|
|
3
|
+
function retryOptions(timeoutMs) {
|
|
4
|
+
return timeoutMs ? { timeoutMs } : undefined;
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
class MobileAndroidPageImpl {
|
|
17
|
-
browserSession;
|
|
18
|
-
pageSession;
|
|
19
|
-
constructor(browserSession, pageSession) {
|
|
20
|
-
this.browserSession = browserSession;
|
|
21
|
-
this.pageSession = pageSession;
|
|
22
|
-
}
|
|
23
|
-
get sessionId() {
|
|
24
|
-
return this.pageSession.page_id;
|
|
6
|
+
class MobileAndroidAppImpl {
|
|
7
|
+
sessionId;
|
|
8
|
+
#runtime;
|
|
9
|
+
#surfaceSessionId;
|
|
10
|
+
#handlePromise = null;
|
|
11
|
+
constructor(runtime, surfaceSessionId, sessionId) {
|
|
12
|
+
this.sessionId = sessionId;
|
|
13
|
+
this.#runtime = runtime;
|
|
14
|
+
this.#surfaceSessionId = surfaceSessionId;
|
|
25
15
|
}
|
|
26
16
|
locator(selector) {
|
|
27
17
|
return new MobileAndroidLocatorImpl(this, normalizeMobileSelectorForTransport(selector));
|
|
28
18
|
}
|
|
29
19
|
async click(selector, options = {}) {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
const handle = await this.#getHandle();
|
|
21
|
+
this.#ensureOpen(handle);
|
|
22
|
+
handle.stream.write({
|
|
23
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
24
|
+
contextSessionId: this.sessionId,
|
|
25
|
+
clickElement: {
|
|
26
|
+
cssSelector: normalizeMobileSelectorForTransport(selector),
|
|
27
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
28
|
+
},
|
|
36
29
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
while (true) {
|
|
31
|
+
const event = await handle.queue.next();
|
|
32
|
+
if (event.elementClicked) {
|
|
33
|
+
return {
|
|
34
|
+
selector: event.elementClicked.cssSelector ?? "",
|
|
35
|
+
note: event.elementClicked.note ?? "",
|
|
36
|
+
bidiSessionId: event.elementClicked.bidiSessionId ?? "",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (event.error?.message) {
|
|
40
|
+
throw new Error(event.error.message);
|
|
41
|
+
}
|
|
42
|
+
if (event.closed) {
|
|
43
|
+
handle.closed = true;
|
|
44
|
+
throw new Error(`android app session ${this.sessionId} closed while clicking`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
async fill(selector, value, options = {}) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const handle = await this.#getHandle();
|
|
50
|
+
this.#ensureOpen(handle);
|
|
51
|
+
handle.stream.write({
|
|
52
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
53
|
+
contextSessionId: this.sessionId,
|
|
54
|
+
fillElement: {
|
|
55
|
+
cssSelector: normalizeMobileSelectorForTransport(selector),
|
|
56
|
+
value,
|
|
57
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
58
|
+
},
|
|
51
59
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
while (true) {
|
|
61
|
+
const event = await handle.queue.next();
|
|
62
|
+
if (event.elementFilled) {
|
|
63
|
+
return {
|
|
64
|
+
selector: event.elementFilled.cssSelector ?? "",
|
|
65
|
+
value: event.elementFilled.value ?? "",
|
|
66
|
+
note: event.elementFilled.note ?? "",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (event.error?.message) {
|
|
70
|
+
throw new Error(event.error.message);
|
|
71
|
+
}
|
|
72
|
+
if (event.closed) {
|
|
73
|
+
handle.closed = true;
|
|
74
|
+
throw new Error(`android app session ${this.sessionId} closed while filling`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async screenshot(options = {}) {
|
|
79
|
+
const handle = await this.#getHandle();
|
|
80
|
+
this.#ensureOpen(handle);
|
|
81
|
+
handle.stream.write({
|
|
82
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
83
|
+
contextSessionId: this.sessionId,
|
|
84
|
+
screenshot: {
|
|
85
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
while (true) {
|
|
89
|
+
const event = await handle.queue.next();
|
|
90
|
+
if (event.screenshotCaptured?.pngData) {
|
|
91
|
+
return {
|
|
92
|
+
pngData: event.screenshotCaptured.pngData,
|
|
93
|
+
note: event.screenshotCaptured.note ?? "",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (event.error?.message) {
|
|
97
|
+
throw new Error(event.error.message);
|
|
98
|
+
}
|
|
99
|
+
if (event.closed) {
|
|
100
|
+
handle.closed = true;
|
|
101
|
+
throw new Error(`android app session ${this.sessionId} closed while capturing screenshot`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async #getHandle() {
|
|
106
|
+
if (!this.#handlePromise) {
|
|
107
|
+
this.#handlePromise = createPageHandle(this.#runtime);
|
|
108
|
+
}
|
|
109
|
+
return this.#handlePromise;
|
|
110
|
+
}
|
|
111
|
+
#ensureOpen(handle) {
|
|
112
|
+
if (handle.closed) {
|
|
113
|
+
throw new Error(`android app session ${this.sessionId} is closed`);
|
|
114
|
+
}
|
|
57
115
|
}
|
|
58
116
|
}
|
|
59
117
|
class MobileAndroidLocatorImpl {
|
|
@@ -74,48 +132,81 @@ class MobileAndroidLocatorImpl {
|
|
|
74
132
|
}
|
|
75
133
|
}
|
|
76
134
|
class MobileAndroidDeviceImpl {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
135
|
+
sessionId;
|
|
136
|
+
surfaceSessionId;
|
|
137
|
+
runtime;
|
|
138
|
+
#stream;
|
|
139
|
+
#queue;
|
|
140
|
+
#closed = false;
|
|
141
|
+
#currentApp;
|
|
142
|
+
constructor(sessionId, surfaceSessionId, runtime, stream, queue, initialAppSessionId) {
|
|
143
|
+
this.sessionId = sessionId;
|
|
144
|
+
this.surfaceSessionId = surfaceSessionId;
|
|
145
|
+
this.runtime = runtime;
|
|
146
|
+
this.#stream = stream;
|
|
147
|
+
this.#queue = queue;
|
|
148
|
+
this.#currentApp = new MobileAndroidAppImpl(runtime, surfaceSessionId, initialAppSessionId);
|
|
149
|
+
}
|
|
150
|
+
app() {
|
|
151
|
+
return this.#currentApp;
|
|
152
|
+
}
|
|
153
|
+
initialApp() {
|
|
154
|
+
return this.#currentApp;
|
|
91
155
|
}
|
|
92
156
|
async launch(options = {}) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
timeout_ms: timeoutMsOf(options),
|
|
157
|
+
this.#ensureOpen();
|
|
158
|
+
this.#stream.write({
|
|
159
|
+
launchApp: {
|
|
160
|
+
apkPath: options.apkPath,
|
|
161
|
+
appId: options.appId,
|
|
162
|
+
launchActivity: options.launchActivity,
|
|
163
|
+
stopBeforeLaunch: options.stopBeforeLaunch ?? false,
|
|
164
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
102
165
|
},
|
|
103
166
|
});
|
|
104
|
-
|
|
105
|
-
|
|
167
|
+
while (true) {
|
|
168
|
+
const event = await this.#queue.next();
|
|
169
|
+
if (event.appLaunched?.appSessionId) {
|
|
170
|
+
this.#currentApp = new MobileAndroidAppImpl(this.runtime, this.surfaceSessionId, event.appLaunched.appSessionId);
|
|
171
|
+
return this.#currentApp;
|
|
172
|
+
}
|
|
173
|
+
if (event.error?.message) {
|
|
174
|
+
throw new Error(event.error.message);
|
|
175
|
+
}
|
|
176
|
+
if (event.closed) {
|
|
177
|
+
this.#closed = true;
|
|
178
|
+
throw new Error(`android device session ${this.sessionId} closed while launching app`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
#ensureOpen() {
|
|
183
|
+
if (this.#closed) {
|
|
184
|
+
throw new Error(`android device session ${this.sessionId} is closed`);
|
|
185
|
+
}
|
|
106
186
|
}
|
|
107
187
|
}
|
|
108
188
|
class MobileAndroidSurfaceImpl {
|
|
109
189
|
async connect(options = {}) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
190
|
+
const runtime = await getRuntime();
|
|
191
|
+
const { stream, queue } = await createBrowserSessionHandle(runtime);
|
|
192
|
+
stream.write({
|
|
193
|
+
connectMobile: {
|
|
194
|
+
platform: 1,
|
|
195
|
+
device: options.device,
|
|
196
|
+
adbEndpoint: options.adbEndpoint,
|
|
197
|
+
preserveAppState: options.preserveAppState ?? false,
|
|
198
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
199
|
+
},
|
|
117
200
|
});
|
|
118
|
-
|
|
201
|
+
while (true) {
|
|
202
|
+
const event = await queue.next();
|
|
203
|
+
if (event.mobileConnected?.initialAppSessionId) {
|
|
204
|
+
return new MobileAndroidDeviceImpl(event.mobileConnected.deviceSessionId ?? event.sessionId ?? "", event.sessionId ?? "", runtime, stream, queue, event.mobileConnected.initialAppSessionId);
|
|
205
|
+
}
|
|
206
|
+
if (event.error?.message) {
|
|
207
|
+
throw new Error(event.error.message);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
119
210
|
}
|
|
120
211
|
}
|
|
121
212
|
export const mobile = {
|
package/dist/page.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, Locator, NavigateResult, Page, PageInfo, PressOptions, PressResult, RuntimeClient, TextResult, WaitForSelectorOptions, WaitForSelectorResult } from "./types.js";
|
|
1
|
+
import type { ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, Locator, NavigateResult, Page, PageInfo, PressOptions, PressResult, RuntimeClient, ScreenshotResult, TextResult, WaitForSelectorOptions, WaitForSelectorResult } from "./types.js";
|
|
2
2
|
export declare class PageImpl implements Page {
|
|
3
3
|
#private;
|
|
4
4
|
constructor(input: PageInfo & {
|
|
@@ -18,8 +18,10 @@ export declare class PageImpl implements Page {
|
|
|
18
18
|
textContent(selector: string, options?: CommandOptions): Promise<TextResult>;
|
|
19
19
|
innerText(selector: string, options?: CommandOptions): Promise<TextResult>;
|
|
20
20
|
waitForSelector(selector: string, options?: WaitForSelectorOptions): Promise<WaitForSelectorResult>;
|
|
21
|
+
screenshot(options?: CommandOptions): Promise<ScreenshotResult>;
|
|
21
22
|
close(): Promise<void>;
|
|
22
23
|
ping(message?: string): Promise<string>;
|
|
23
24
|
pageInfo(): PageInfo;
|
|
24
25
|
navigate(url: string, options?: CommandOptions): Promise<NavigateResult>;
|
|
26
|
+
dispose(): void;
|
|
25
27
|
}
|