@e2e-dev/mobile 0.9.1 → 0.9.2
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 +7 -5
- package/dist/.build.json +1 -1
- package/dist/device.d.ts +2 -2
- package/dist/errors.d.ts +6 -4
- package/dist/errors.js +23 -8
- package/dist/links.d.ts +11 -6
- package/dist/links.js +13 -8
- package/dist/nodes.d.ts +7 -41
- package/dist/options.d.ts +3 -2
- package/dist/support.d.ts +2 -8
- package/dist/surface.js +9 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @e2e-dev/mobile
|
|
2
2
|
|
|
3
3
|
The mobile engine for [`e2e`](https://www.npmjs.com/package/e2e), built on
|
|
4
|
-
[agent-device](https://github.com/callstack/agent-device): iOS simulators
|
|
5
|
-
Android emulators through the same `e2e/engine` contract the browser engine
|
|
4
|
+
[agent-device](https://github.com/callstack/agent-device): iOS simulators,
|
|
5
|
+
Android emulators, and connected phones through the same `e2e/engine` contract the browser engine
|
|
6
6
|
implements. A test written against `screen`, `expect`, `app`, and `agent` runs
|
|
7
7
|
on a device target unchanged; nothing in `e2e` core knows this package exists.
|
|
8
8
|
|
|
@@ -18,7 +18,8 @@ npm install --save-dev e2e @e2e-dev/mobile
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
`agent-device` needs Xcode with an iOS simulator runtime, or the Android SDK
|
|
21
|
-
with an emulator.
|
|
21
|
+
with an emulator. A phone needs Developer Mode and runner signing on iOS, or
|
|
22
|
+
USB debugging authorized on Android (see [Physical devices](https://e2e.tester.army/docs/physical-devices)). Run `npx agent-device doctor` once before handing the target
|
|
22
23
|
to the runner.
|
|
23
24
|
|
|
24
25
|
```ts title="e2e.config.ts"
|
|
@@ -68,7 +69,7 @@ the other old app options are `INVALID_CONFIG` naming their key under `app`.
|
|
|
68
69
|
| Option | Meaning |
|
|
69
70
|
| --- | --- |
|
|
70
71
|
| `platform` | `'ios'` or `'android'`. |
|
|
71
|
-
| `device` | Simulator or emulator name or UDID. A list is a pool: one worker per entry, worker slot `n` driving the `n`th. Omitted, every booted device of the platform is the pool, as many as the run has slots. |
|
|
72
|
+
| `device` | Simulator or emulator name or UDID, or a connected phone's name. A list is a pool: one worker per entry, worker slot `n` driving the `n`th. Omitted, every booted device of the platform is the pool, as many as the run has slots. |
|
|
72
73
|
| `session` | agent-device session name, before the worker slot: slot `n` drives its device under `<session>-<n>`, `e2e-<target name>-<n>` by default. One run per session at a time. |
|
|
73
74
|
| `snapshot` | `'full'` (default, includes static text) or `'interactive'` (actionable nodes only). |
|
|
74
75
|
| `settle` | For agent actions: milliseconds the UI must hold still after an action before the agent observes again, default `150`; `false` skips the wait. A test's own steps never settle; `expect` verifies their outcome. |
|
|
@@ -145,7 +146,8 @@ test, for upgrade and fresh-install paths the target's `app.appPath` cannot
|
|
|
145
146
|
express.
|
|
146
147
|
A plain install replaces the binary and keeps its data; `reinstall: true`
|
|
147
148
|
removes the app named by `app` (default: the pinned app) first. It resolves to
|
|
148
|
-
the bundle id or package to `openApp` the build by
|
|
149
|
+
the bundle id or package to `openApp` the build by, else the `app` passed in;
|
|
150
|
+
with no reported id and no `app`, it fails with `ENGINE_FAILURE`. `openApp` takes an app id,
|
|
149
151
|
never a link; `openLink` opens one, under the navigation rule.
|
|
150
152
|
|
|
151
153
|
## Agent tools
|
package/dist/.build.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.9.
|
|
1
|
+
{"version":"0.9.2"}
|
package/dist/device.d.ts
CHANGED
|
@@ -82,8 +82,8 @@ export interface Device {
|
|
|
82
82
|
* a web link the app does not claim goes to Safari, and the next
|
|
83
83
|
* observation brings the app back. Android starts the link on that
|
|
84
84
|
* package. Without an app, Android lets the OS route the link; iOS needs
|
|
85
|
-
* one (`INVALID_ARGUMENT` without). `file:`, `data:`,
|
|
86
|
-
* links are `POLICY_DENIED`.
|
|
85
|
+
* one (`INVALID_ARGUMENT` without). `file:`, `data:`, `javascript:`,
|
|
86
|
+
* `view-source:`, `blob:`, and `filesystem:` links are `POLICY_DENIED`.
|
|
87
87
|
*/
|
|
88
88
|
openLink(url: string, options?: {
|
|
89
89
|
app?: string;
|
package/dist/errors.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* | no active session / session not found / requires a session | INVALID_STATE |
|
|
9
9
|
* | UNSUPPORTED_OPERATION, NOT_IMPLEMENTED, UNSUPPORTED_PLATFORM | UNSUPPORTED_CAPABILITY |
|
|
10
10
|
* | "not supported on this device" under any code | UNSUPPORTED_CAPABILITY |
|
|
11
|
-
* | a ref
|
|
11
|
+
* | a stale-ref refusal, by `details.reason` (action paths only) | NODE_STALE (retryable) |
|
|
12
12
|
* | the iOS runner busy, wedged, or past its watchdog | ENGINE_FAILURE, naming the |
|
|
13
13
|
* | a snapshot the iOS runner acquired but could not present | runner and the recovery |
|
|
14
14
|
* | anything else, agent-device's own timeouts included | ENGINE_FAILURE with the text |
|
|
@@ -53,8 +53,10 @@ export declare function isSnapshotPresentationFailure(error: unknown): boolean;
|
|
|
53
53
|
*/
|
|
54
54
|
export declare function runCommand<T>(label: string, work: () => Promise<T>, signal: AbortSignal, where?: string): Promise<T>;
|
|
55
55
|
/**
|
|
56
|
-
* Like translateError, but a ref
|
|
57
|
-
* `NODE_STALE`: nothing was dispatched, so the harness may
|
|
58
|
-
* re-resolve the node instead of failing the action.
|
|
56
|
+
* Like translateError, but a ref agent-device refused as stale becomes
|
|
57
|
+
* retryable `NODE_STALE`: nothing was dispatched, so the harness may
|
|
58
|
+
* re-observe and re-resolve the node instead of failing the action. Keyed on
|
|
59
|
+
* the reason alone: agent-device marks a drag's stale ref `dispatched:
|
|
60
|
+
* 'unknown'` although it refuses it before the gesture.
|
|
59
61
|
*/
|
|
60
62
|
export declare function staleOr(cause: unknown, operation: string, where?: string): Error;
|
package/dist/errors.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* | no active session / session not found / requires a session | INVALID_STATE |
|
|
9
9
|
* | UNSUPPORTED_OPERATION, NOT_IMPLEMENTED, UNSUPPORTED_PLATFORM | UNSUPPORTED_CAPABILITY |
|
|
10
10
|
* | "not supported on this device" under any code | UNSUPPORTED_CAPABILITY |
|
|
11
|
-
* | a ref
|
|
11
|
+
* | a stale-ref refusal, by `details.reason` (action paths only) | NODE_STALE (retryable) |
|
|
12
12
|
* | the iOS runner busy, wedged, or past its watchdog | ENGINE_FAILURE, naming the |
|
|
13
13
|
* | a snapshot the iOS runner acquired but could not present | runner and the recovery |
|
|
14
14
|
* | anything else, agent-device's own timeouts included | ENGINE_FAILURE with the text |
|
|
@@ -61,7 +61,20 @@ const CLI_ADVICE = /--help|command arguments/i;
|
|
|
61
61
|
const NO_SESSION_PATTERN = /no active (?:app )?session|requires an active session|session\b.*\bnot found|open an app first|no app (?:is )?open/i;
|
|
62
62
|
const UNSUPPORTED_CODES = new Set(['UNSUPPORTED_OPERATION', 'NOT_IMPLEMENTED', 'UNSUPPORTED_PLATFORM']);
|
|
63
63
|
const UNSUPPORTED_PATTERN = /\b(?:is )?not supported\b|\bunsupported\b/i;
|
|
64
|
-
|
|
64
|
+
/**
|
|
65
|
+
* The `details.reason` values agent-device refuses an `@ref` with: the ref
|
|
66
|
+
* names no node of the session's tree, or belongs to a capture the session
|
|
67
|
+
* has since moved past (a newer snapshot, or an action that expired its refs).
|
|
68
|
+
* agent-device raises each one while resolving or admitting the ref, before
|
|
69
|
+
* the action reaches the device.
|
|
70
|
+
*/
|
|
71
|
+
const STALE_REF_REASONS = new Set([
|
|
72
|
+
'ref_not_found',
|
|
73
|
+
'ref_frame_expired',
|
|
74
|
+
'ref_generation_mismatch',
|
|
75
|
+
'plain_ref_requires_complete_frame',
|
|
76
|
+
'ref_not_issued',
|
|
77
|
+
]);
|
|
65
78
|
/**
|
|
66
79
|
* What the iOS automation runner reported about itself, by the code
|
|
67
80
|
* agent-device emits for it: `RUNNER_WEDGED` at the top level, `RUNNER_BUSY`
|
|
@@ -207,16 +220,18 @@ export async function runCommand(label, work, signal, where) {
|
|
|
207
220
|
}
|
|
208
221
|
}
|
|
209
222
|
/**
|
|
210
|
-
* Like translateError, but a ref
|
|
211
|
-
* `NODE_STALE`: nothing was dispatched, so the harness may
|
|
212
|
-
* re-resolve the node instead of failing the action.
|
|
223
|
+
* Like translateError, but a ref agent-device refused as stale becomes
|
|
224
|
+
* retryable `NODE_STALE`: nothing was dispatched, so the harness may
|
|
225
|
+
* re-observe and re-resolve the node instead of failing the action. Keyed on
|
|
226
|
+
* the reason alone: agent-device marks a drag's stale ref `dispatched:
|
|
227
|
+
* 'unknown'` although it refuses it before the gesture.
|
|
213
228
|
*/
|
|
214
229
|
export function staleOr(cause, operation, where) {
|
|
215
230
|
if (isClassified(cause))
|
|
216
231
|
return cause;
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
return new EngineError('NODE_STALE', `${operation}: ${
|
|
232
|
+
const { reason } = details(cause);
|
|
233
|
+
if (typeof reason === 'string' && STALE_REF_REASONS.has(reason)) {
|
|
234
|
+
return new EngineError('NODE_STALE', `${operation}: ${message(cause)}`, { retryable: true, cause });
|
|
220
235
|
}
|
|
221
236
|
return translateError(cause, operation, where);
|
|
222
237
|
}
|
package/dist/links.d.ts
CHANGED
|
@@ -5,22 +5,27 @@
|
|
|
5
5
|
*
|
|
6
6
|
* The runner's own rule (`resolveNavigationUrl`, reached by a fixture as
|
|
7
7
|
* `context.app.resolveUrl`) first demands an app URL, which a device engine
|
|
8
|
-
* never declares,
|
|
9
|
-
*
|
|
8
|
+
* never declares, and admits http(s) alone, where a device link is any app's
|
|
9
|
+
* custom scheme. So the check here is a list of refused schemes: the ones
|
|
10
|
+
* that read local content or inline a document, and the browser wrappers
|
|
11
|
+
* (`view-source:file:...`, `blob:`, `filesystem:`) that carry one inside.
|
|
10
12
|
*/
|
|
11
13
|
/** Whether agent-device would open this string as a URL rather than resolve it as an app. */
|
|
12
14
|
export declare function isLink(value: string): boolean;
|
|
13
15
|
/**
|
|
14
16
|
* Parses a link a test asked to open. A string that is not an absolute URL
|
|
15
|
-
* is `INVALID_ARGUMENT`; a `file:`, `data:`,
|
|
16
|
-
* `POLICY_DENIED`, as it is for `app.open`
|
|
17
|
+
* is `INVALID_ARGUMENT`; a `file:`, `data:`, `javascript:`, `view-source:`,
|
|
18
|
+
* `blob:`, or `filesystem:` link is `POLICY_DENIED`, as it is for `app.open`
|
|
19
|
+
* on the web. The message never echoes the input: a malformed link can carry
|
|
20
|
+
* a magic-link token in its query, path, or userinfo, and nothing about a
|
|
21
|
+
* string that failed to parse says which part is safe to repeat.
|
|
17
22
|
*/
|
|
18
23
|
export declare function linkTarget(input: string): URL;
|
|
19
24
|
/**
|
|
20
25
|
* Refuses a link handed to `openApp`, which opens an app by bundle id,
|
|
21
26
|
* package, or display name. agent-device opens any `scheme:rest` string as
|
|
22
|
-
* a URL, so the check runs before the device sees it: a
|
|
23
|
-
*
|
|
27
|
+
* a URL, so the check runs before the device sees it: a link with a
|
|
28
|
+
* forbidden scheme is `POLICY_DENIED` as it is for `openLink`, any
|
|
24
29
|
* other link is `INVALID_ARGUMENT` pointing at `openLink`. The message
|
|
25
30
|
* never echoes the link, whose query may carry a magic-link token.
|
|
26
31
|
*/
|
package/dist/links.js
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
*
|
|
6
6
|
* The runner's own rule (`resolveNavigationUrl`, reached by a fixture as
|
|
7
7
|
* `context.app.resolveUrl`) first demands an app URL, which a device engine
|
|
8
|
-
* never declares,
|
|
9
|
-
*
|
|
8
|
+
* never declares, and admits http(s) alone, where a device link is any app's
|
|
9
|
+
* custom scheme. So the check here is a list of refused schemes: the ones
|
|
10
|
+
* that read local content or inline a document, and the browser wrappers
|
|
11
|
+
* (`view-source:file:...`, `blob:`, `filesystem:`) that carry one inside.
|
|
10
12
|
*/
|
|
11
13
|
import { ConfigurationError, TestError } from 'e2e/engine';
|
|
12
|
-
const FORBIDDEN_PROTOCOLS = new Set(['file:', 'data:', 'javascript:']);
|
|
14
|
+
const FORBIDDEN_PROTOCOLS = new Set(['file:', 'data:', 'javascript:', 'view-source:', 'blob:', 'filesystem:']);
|
|
13
15
|
/**
|
|
14
16
|
* What agent-device opens as a URL instead of resolving as an app: a
|
|
15
17
|
* `scheme:rest` string with no whitespace. Every string the device would
|
|
@@ -28,8 +30,11 @@ function denyForbiddenScheme(protocol) {
|
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* Parses a link a test asked to open. A string that is not an absolute URL
|
|
31
|
-
* is `INVALID_ARGUMENT`; a `file:`, `data:`,
|
|
32
|
-
* `POLICY_DENIED`, as it is for `app.open`
|
|
33
|
+
* is `INVALID_ARGUMENT`; a `file:`, `data:`, `javascript:`, `view-source:`,
|
|
34
|
+
* `blob:`, or `filesystem:` link is `POLICY_DENIED`, as it is for `app.open`
|
|
35
|
+
* on the web. The message never echoes the input: a malformed link can carry
|
|
36
|
+
* a magic-link token in its query, path, or userinfo, and nothing about a
|
|
37
|
+
* string that failed to parse says which part is safe to repeat.
|
|
33
38
|
*/
|
|
34
39
|
export function linkTarget(input) {
|
|
35
40
|
let url;
|
|
@@ -37,7 +42,7 @@ export function linkTarget(input) {
|
|
|
37
42
|
url = new URL(input);
|
|
38
43
|
}
|
|
39
44
|
catch {
|
|
40
|
-
throw new TestError('INVALID_ARGUMENT',
|
|
45
|
+
throw new TestError('INVALID_ARGUMENT', 'openLink needs an absolute URL such as myapp://orders/42 or https://example.com/verify');
|
|
41
46
|
}
|
|
42
47
|
denyForbiddenScheme(url.protocol);
|
|
43
48
|
return url;
|
|
@@ -45,8 +50,8 @@ export function linkTarget(input) {
|
|
|
45
50
|
/**
|
|
46
51
|
* Refuses a link handed to `openApp`, which opens an app by bundle id,
|
|
47
52
|
* package, or display name. agent-device opens any `scheme:rest` string as
|
|
48
|
-
* a URL, so the check runs before the device sees it: a
|
|
49
|
-
*
|
|
53
|
+
* a URL, so the check runs before the device sees it: a link with a
|
|
54
|
+
* forbidden scheme is `POLICY_DENIED` as it is for `openLink`, any
|
|
50
55
|
* other link is `INVALID_ARGUMENT` pointing at `openLink`. The message
|
|
51
56
|
* never echoes the link, whose query may carry a magic-link token.
|
|
52
57
|
*/
|
package/dist/nodes.d.ts
CHANGED
|
@@ -6,48 +6,14 @@
|
|
|
6
6
|
* vocabulary `screen.getByRole` and trace relocation speak, and mints the
|
|
7
7
|
* ids the surface owns.
|
|
8
8
|
*/
|
|
9
|
+
import type { SnapshotNode } from 'agent-device';
|
|
9
10
|
import type { SemanticNode, ViewportSize } from 'e2e/engine';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
readonly depth?: number;
|
|
17
|
-
readonly type?: string;
|
|
18
|
-
readonly role?: string;
|
|
19
|
-
readonly label?: string;
|
|
20
|
-
readonly value?: string;
|
|
21
|
-
/** True while a text field shows its placeholder; the runner then reports the placeholder as the value. */
|
|
22
|
-
readonly hintShowing?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Android's content description when it differs from `label`: the
|
|
25
|
-
* accessible name an app set beside visible text (agent-device 0.21.14+).
|
|
26
|
-
*/
|
|
27
|
-
readonly contentDescription?: string;
|
|
28
|
-
/** The field's placeholder text, showing or not (agent-device 0.21.16+). */
|
|
29
|
-
readonly placeholder?: string;
|
|
30
|
-
/** The checked state of a checkable control; absent for one that cannot be checked or an older helper. */
|
|
31
|
-
readonly checked?: boolean;
|
|
32
|
-
/** The accessibility heading flag an app set on the node (Android). */
|
|
33
|
-
readonly heading?: boolean;
|
|
34
|
-
/** The localized role description an app set beside the native class, verbatim (`Tab`, `Tab List`). */
|
|
35
|
-
readonly roleDescription?: string;
|
|
36
|
-
readonly identifier?: string;
|
|
37
|
-
readonly rect?: Rect;
|
|
38
|
-
readonly enabled?: boolean;
|
|
39
|
-
readonly selected?: boolean;
|
|
40
|
-
readonly focused?: boolean;
|
|
41
|
-
/** Native accessibility facts; absent means unavailable, not false. */
|
|
42
|
-
readonly editable?: boolean;
|
|
43
|
-
readonly password?: boolean;
|
|
44
|
-
readonly visibleToUser?: boolean;
|
|
45
|
-
readonly hittable?: boolean;
|
|
46
|
-
readonly appName?: string;
|
|
47
|
-
readonly windowTitle?: string;
|
|
48
|
-
/** The package (Android) or bundle id (iOS) of the window the node belongs to, when agent-device reports it. */
|
|
49
|
-
readonly bundleId?: string;
|
|
50
|
-
}
|
|
11
|
+
/**
|
|
12
|
+
* One agent-device snapshot node as this engine reads it: agent-device's own
|
|
13
|
+
* node type, every field optional, since the projection tolerates each one
|
|
14
|
+
* missing (a fixture, a producer that does not read it).
|
|
15
|
+
*/
|
|
16
|
+
export type RawNode = Readonly<Partial<SnapshotNode>>;
|
|
51
17
|
/** One projected node with what the surface needs to act on it and to answer selector terms. */
|
|
52
18
|
export interface ProjectedNode {
|
|
53
19
|
readonly id: string;
|
package/dist/options.d.ts
CHANGED
|
@@ -33,8 +33,9 @@ export interface MobileOptions {
|
|
|
33
33
|
/** Platform the target's device runs. */
|
|
34
34
|
readonly platform: MobilePlatform;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
* serial (`emulator-5554`)
|
|
36
|
+
* Device to use: a simulator or emulator by name, simulator UDID, or
|
|
37
|
+
* emulator serial (`emulator-5554`), or a connected phone by name. A list
|
|
38
|
+
* is a pool: the
|
|
38
39
|
* engine declares one worker per entry and worker slot `n` drives the
|
|
39
40
|
* `n`th, so `workers` at or above the pool size runs the target's files
|
|
40
41
|
* across every device at once. Omitted, the pool is every booted device of
|
package/dist/support.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Shared helpers for the agent-device engine: error constructors, filenames, PNG headers, gestures, the screen location and size. */
|
|
2
|
+
import type { CaptureScreenshotResult } from 'agent-device';
|
|
2
3
|
import { EngineError, type Momentum, type ScrollDirection, type ViewportSize } from 'e2e/engine';
|
|
3
4
|
export interface Point {
|
|
4
5
|
readonly x: number;
|
|
@@ -46,14 +47,7 @@ export declare function swipeWithin(rect: Rect, direction: ScrollDirection, mome
|
|
|
46
47
|
*/
|
|
47
48
|
export declare function screenLocation(app: string | undefined, title: string | undefined): string | undefined;
|
|
48
49
|
/** The screenshot fields a viewport probe reads off agent-device's response. */
|
|
49
|
-
export
|
|
50
|
-
readonly path?: string;
|
|
51
|
-
readonly width?: number;
|
|
52
|
-
readonly height?: number;
|
|
53
|
-
readonly logicalWidth?: number;
|
|
54
|
-
readonly logicalHeight?: number;
|
|
55
|
-
readonly pixelDensity?: number;
|
|
56
|
-
}
|
|
50
|
+
export type RawScreenshotResult = Partial<Pick<CaptureScreenshotResult, 'path' | 'width' | 'height' | 'logicalWidth' | 'logicalHeight' | 'pixelDensity'>>;
|
|
57
51
|
/**
|
|
58
52
|
* The device's logical screen size as its screenshot reports it, in points:
|
|
59
53
|
* the logical dimensions when given, else the pixel dimensions over the
|
package/dist/surface.js
CHANGED
|
@@ -634,11 +634,15 @@ export class AgentDeviceSurface {
|
|
|
634
634
|
if (options.reinstall === true && app === undefined) {
|
|
635
635
|
throw invalidState("reinstall needs an app: pass `app`, or pin one with the target's app.bundleId or app.appPath");
|
|
636
636
|
}
|
|
637
|
-
const result =
|
|
637
|
+
const result = await this.command(`install ${resolved}`, (client) => options.reinstall === true && app !== undefined
|
|
638
638
|
? client.apps.reinstall({ ...selection, app, appPath: resolved })
|
|
639
|
-
: client.apps.install({ ...selection, ...(app === undefined ? {} : { app }), appPath: resolved }), signal)
|
|
639
|
+
: client.apps.install({ ...selection, ...(app === undefined ? {} : { app }), appPath: resolved }), signal);
|
|
640
640
|
const identity = result.bundleId ?? result.package ?? result.appId;
|
|
641
|
-
const
|
|
641
|
+
const opensBy = identity ?? app;
|
|
642
|
+
if (opensBy === undefined) {
|
|
643
|
+
throw new EngineError('ENGINE_FAILURE', `installed ${resolved}, but agent-device reported no bundle id or package for it, so nothing can open it: name the app with the target's \`app.bundleId\` or installApp's \`app\` option`, { retryable: false });
|
|
644
|
+
}
|
|
645
|
+
const installed = { app: opensBy, ...(identity === undefined ? {} : { bundleId: identity }) };
|
|
642
646
|
// The engine's own build, installed: without `app`, this is what `app.open()` launches from here on.
|
|
643
647
|
if (engineBuild)
|
|
644
648
|
this.installedApp = installed.app;
|
|
@@ -1133,7 +1137,7 @@ export class AgentDeviceSurface {
|
|
|
1133
1137
|
async restart(operation) {
|
|
1134
1138
|
const app = this.pinnedApp;
|
|
1135
1139
|
if (app === undefined)
|
|
1136
|
-
throw unsupported(`app
|
|
1140
|
+
throw unsupported(`launching the app needs the target's \`app.bundleId\`, or ${UNINSTALLED_BUILD}`);
|
|
1137
1141
|
await this.openApp(app, { relaunch: true }, operation.signal);
|
|
1138
1142
|
}
|
|
1139
1143
|
/** Clears the pinned app's persisted state and relaunches it: the device equivalent of a fresh context. */
|
|
@@ -1199,7 +1203,7 @@ export class AgentDeviceSurface {
|
|
|
1199
1203
|
const directory = mkdtempSync(path.join(tmpdir(), 'e2e-agent-device-'));
|
|
1200
1204
|
const file = path.join(directory, 'screenshot.png');
|
|
1201
1205
|
try {
|
|
1202
|
-
return await read(
|
|
1206
|
+
return await read(await client.capture.screenshot({ path: file }), file);
|
|
1203
1207
|
}
|
|
1204
1208
|
finally {
|
|
1205
1209
|
rmSync(directory, { recursive: true, force: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e2e-dev/mobile",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Mobile engine (iOS and Android) for e2e agentic end-to-end testing, built on agent-device",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"e2e",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"NOTICE"
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"agent-device": "0.21.
|
|
54
|
+
"agent-device": "0.21.20",
|
|
55
55
|
"pngjs": "7.0.0",
|
|
56
56
|
"zod": "4.6.1"
|
|
57
57
|
},
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@types/node": "26.6.2",
|
|
69
69
|
"@types/pngjs": "6.0.5",
|
|
70
70
|
"ai": "7.0.107",
|
|
71
|
-
"e2e": "0.
|
|
71
|
+
"e2e": "0.17.0",
|
|
72
72
|
"typescript": "7.0.2",
|
|
73
73
|
"vitest": "5.0.1"
|
|
74
74
|
},
|