@e2edev/mobile 0.8.0-canary-20260921180210
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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +149 -0
- package/dist/.build.json +1 -0
- package/dist/actions.d.ts +29 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +62 -0
- package/dist/actions.js.map +1 -0
- package/dist/bindings.d.ts +57 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +79 -0
- package/dist/bindings.js.map +1 -0
- package/dist/device.d.ts +77 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +101 -0
- package/dist/device.js.map +1 -0
- package/dist/engine.d.ts +17 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +92 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +95 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/locate.d.ts +11 -0
- package/dist/locate.d.ts.map +1 -0
- package/dist/locate.js +115 -0
- package/dist/locate.js.map +1 -0
- package/dist/nodes.d.ts +86 -0
- package/dist/nodes.d.ts.map +1 -0
- package/dist/nodes.js +315 -0
- package/dist/nodes.js.map +1 -0
- package/dist/options.d.ts +93 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +7 -0
- package/dist/options.js.map +1 -0
- package/dist/png.d.ts +4 -0
- package/dist/png.d.ts.map +1 -0
- package/dist/png.js +25 -0
- package/dist/png.js.map +1 -0
- package/dist/pool.d.ts +72 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +185 -0
- package/dist/pool.js.map +1 -0
- package/dist/provider.d.ts +105 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +98 -0
- package/dist/provider.js.map +1 -0
- package/dist/selector.d.ts +17 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/selector.js +84 -0
- package/dist/selector.js.map +1 -0
- package/dist/support.d.ts +58 -0
- package/dist/support.d.ts.map +1 -0
- package/dist/support.js +82 -0
- package/dist/support.js.map +1 -0
- package/dist/surface.d.ts +243 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +837 -0
- package/dist/surface.js.map +1 -0
- package/dist/tools.d.ts +24 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +90 -0
- package/dist/tools.js.map +1 -0
- package/package.json +83 -0
package/dist/device.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `device` fixture: deterministic device management this engine
|
|
3
|
+
* contributes. Not an agent tool; a test calls these directly to arrange or
|
|
4
|
+
* assert device state, and the harness records each call as a
|
|
5
|
+
* `device.<method>` step bounded by the action timeout.
|
|
6
|
+
*/
|
|
7
|
+
import type { EngineFixtureContext, Locator } from 'e2e/engine';
|
|
8
|
+
import type { AgentDeviceSurface, InstallAppOptions, InstalledApp } from './surface.ts';
|
|
9
|
+
/** Permissions agent-device can grant, deny, or reset on an open app. */
|
|
10
|
+
export type DevicePermission = 'camera' | 'microphone' | 'photos' | 'contacts' | 'notifications' | 'calendar' | 'location' | 'reminders' | 'motion' | 'siri' | 'media-library';
|
|
11
|
+
/** Orientations `setOrientation` accepts. */
|
|
12
|
+
export type DeviceOrientation = 'portrait' | 'portrait-upside-down' | 'landscape-left' | 'landscape-right';
|
|
13
|
+
export type BiometricSensor = 'faceid' | 'touchid' | 'fingerprint';
|
|
14
|
+
export interface ForegroundApp {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly bundleId?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Deterministic device management exposed to tests as `device`. */
|
|
19
|
+
export interface Device {
|
|
20
|
+
/**
|
|
21
|
+
* A locator from an agent-device selector (`'id=SW_VERSION_SPECIFIER'`,
|
|
22
|
+
* `'role=StaticText label="26.2"'`), for nodes the closed `screen` query
|
|
23
|
+
* vocabulary cannot name. Same polling and strictness as any locator.
|
|
24
|
+
*/
|
|
25
|
+
locator(selector: string): Locator;
|
|
26
|
+
/** Toggles the device's Wi-Fi. */
|
|
27
|
+
setNetwork(state: 'online' | 'offline'): Promise<void>;
|
|
28
|
+
/** Toggles airplane mode. */
|
|
29
|
+
setAirplaneMode(enabled: boolean): Promise<void>;
|
|
30
|
+
/** Grants, denies, or resets one permission for the open app. */
|
|
31
|
+
setPermission(permission: DevicePermission, state: 'grant' | 'deny' | 'reset'): Promise<void>;
|
|
32
|
+
/** Sets the simulated location. */
|
|
33
|
+
setLocation(coordinates: {
|
|
34
|
+
latitude: number;
|
|
35
|
+
longitude: number;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
/** Turns simulated location off. */
|
|
38
|
+
clearLocation(): Promise<void>;
|
|
39
|
+
/** Sets the system appearance. */
|
|
40
|
+
setAppearance(mode: 'light' | 'dark'): Promise<void>;
|
|
41
|
+
/** Rotates the device. */
|
|
42
|
+
setOrientation(orientation: DeviceOrientation): Promise<void>;
|
|
43
|
+
/** Simulates one biometric attempt on the open app. */
|
|
44
|
+
setBiometrics(sensor: BiometricSensor, result: 'match' | 'nonmatch'): Promise<void>;
|
|
45
|
+
/** Enrolls or unenrolls the simulator's Face ID or Touch ID. */
|
|
46
|
+
enrollBiometrics(sensor: 'faceid' | 'touchid', enrolled: boolean): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Installs a build (an iOS `.app` bundle or an Android `.apk`, resolved
|
|
49
|
+
* against the project root) on the device. `reinstall: true` removes
|
|
50
|
+
* the app first so it starts with no data; a plain install replaces the
|
|
51
|
+
* binary and keeps its data. Resolves to the identity to `openApp` it by.
|
|
52
|
+
*/
|
|
53
|
+
installApp(appPath: string, options?: InstallAppOptions): Promise<InstalledApp>;
|
|
54
|
+
/** Brings an app to the foreground; `relaunch` restarts it fresh. */
|
|
55
|
+
openApp(app: string, options?: {
|
|
56
|
+
relaunch?: boolean;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/** Closes the session's current app. */
|
|
59
|
+
closeApp(): Promise<void>;
|
|
60
|
+
/** The app currently in the foreground of the session. */
|
|
61
|
+
foregroundApp(): Promise<ForegroundApp>;
|
|
62
|
+
/** Sends the device to its home screen. */
|
|
63
|
+
home(): Promise<void>;
|
|
64
|
+
/** Navigates back once (in-app back). */
|
|
65
|
+
back(): Promise<void>;
|
|
66
|
+
/** Accepts or dismisses the visible system alert. */
|
|
67
|
+
alert(action: 'accept' | 'dismiss'): Promise<void>;
|
|
68
|
+
/** Dismisses the soft keyboard. */
|
|
69
|
+
dismissKeyboard(): Promise<void>;
|
|
70
|
+
/** Reads the clipboard. */
|
|
71
|
+
clipboard(): Promise<string>;
|
|
72
|
+
/** Writes the clipboard. */
|
|
73
|
+
setClipboard(text: string): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
/** Builds the device fixture for one attempt. */
|
|
76
|
+
export declare function createDeviceFixture(surface: AgentDeviceSurface, context: EngineFixtureContext): Device;
|
|
77
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|
package/dist/device.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `device` fixture: deterministic device management this engine
|
|
3
|
+
* contributes. Not an agent tool; a test calls these directly to arrange or
|
|
4
|
+
* assert device state, and the harness records each call as a
|
|
5
|
+
* `device.<method>` step bounded by the action timeout.
|
|
6
|
+
*/
|
|
7
|
+
/** Builds the device fixture for one attempt. */
|
|
8
|
+
export function createDeviceFixture(surface, context) {
|
|
9
|
+
const device = {
|
|
10
|
+
locator: (selector) => context.locator({ kind: 'selector', selector }),
|
|
11
|
+
async setNetwork(state) {
|
|
12
|
+
await surface.command('device.setNetwork', (client) => client.settings.update({ setting: 'wifi', state: state === 'offline' ? 'off' : 'on' }), context.signal);
|
|
13
|
+
},
|
|
14
|
+
async setAirplaneMode(enabled) {
|
|
15
|
+
await surface.command('device.setAirplaneMode', (client) => client.settings.update({ setting: 'airplane', state: enabled ? 'on' : 'off' }), context.signal);
|
|
16
|
+
},
|
|
17
|
+
async setPermission(permission, state) {
|
|
18
|
+
await surface.command('device.setPermission', (client) => client.settings.update({ setting: 'permission', permission, state }), context.signal);
|
|
19
|
+
},
|
|
20
|
+
async setLocation({ latitude, longitude }) {
|
|
21
|
+
await surface.command('device.setLocation', (client) => client.settings.update({ setting: 'location', state: 'set', latitude, longitude }), context.signal);
|
|
22
|
+
},
|
|
23
|
+
async clearLocation() {
|
|
24
|
+
await surface.command('device.clearLocation', (client) => client.settings.update({ setting: 'location', state: 'off' }), context.signal);
|
|
25
|
+
},
|
|
26
|
+
async setAppearance(mode) {
|
|
27
|
+
await surface.command('device.setAppearance', (client) => client.settings.update({ setting: 'appearance', state: mode }), context.signal);
|
|
28
|
+
},
|
|
29
|
+
async setOrientation(orientation) {
|
|
30
|
+
await surface.command('device.setOrientation', (client) => client.command.orientation({ orientation }), context.signal);
|
|
31
|
+
},
|
|
32
|
+
async setBiometrics(sensor, result) {
|
|
33
|
+
await surface.command('device.setBiometrics', (client) => sensor === 'fingerprint'
|
|
34
|
+
? client.settings.update({ setting: 'fingerprint', state: result })
|
|
35
|
+
: client.settings.update({ setting: sensor, state: result }), context.signal);
|
|
36
|
+
},
|
|
37
|
+
async enrollBiometrics(sensor, enrolled) {
|
|
38
|
+
await surface.command('device.enrollBiometrics', (client) => client.settings.update({ setting: sensor, state: enrolled ? 'enroll' : 'unenroll' }), context.signal);
|
|
39
|
+
},
|
|
40
|
+
async installApp(appPath, options) {
|
|
41
|
+
return surface.installApp(appPath, options ?? {}, context.signal);
|
|
42
|
+
},
|
|
43
|
+
async openApp(app, options) {
|
|
44
|
+
await surface.openApp(app, options?.relaunch === true, context.signal);
|
|
45
|
+
},
|
|
46
|
+
async closeApp() {
|
|
47
|
+
await surface.command('device.closeApp', (client) => client.apps.close({}), context.signal);
|
|
48
|
+
},
|
|
49
|
+
async foregroundApp() {
|
|
50
|
+
const state = await surface.command('device.foregroundApp', (client) => client.command.appState({}), context.signal);
|
|
51
|
+
if ('package' in state)
|
|
52
|
+
return { name: state.package, bundleId: state.package };
|
|
53
|
+
return {
|
|
54
|
+
name: state.appName,
|
|
55
|
+
...(state.appBundleId === undefined ? {} : { bundleId: state.appBundleId }),
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
async home() {
|
|
59
|
+
await surface.command('device.home', (client) => client.command.home({}), context.signal);
|
|
60
|
+
},
|
|
61
|
+
async back() {
|
|
62
|
+
await surface.command('device.back', (client) => client.command.back({ ...surface.settleOptions }), context.signal);
|
|
63
|
+
},
|
|
64
|
+
async alert(action) {
|
|
65
|
+
await surface.command('device.alert', (client) => client.command.alert({ action }), context.signal);
|
|
66
|
+
},
|
|
67
|
+
async dismissKeyboard() {
|
|
68
|
+
await surface.command('device.dismissKeyboard', (client) => client.command.keyboard({ action: 'dismiss' }), context.signal);
|
|
69
|
+
},
|
|
70
|
+
async clipboard() {
|
|
71
|
+
const result = await surface.command('device.clipboard', (client) => client.command.clipboard({ action: 'read' }), context.signal);
|
|
72
|
+
return result.action === 'read' ? result.text : '';
|
|
73
|
+
},
|
|
74
|
+
async setClipboard(text) {
|
|
75
|
+
await surface.command('device.setClipboard', (client) => client.command.clipboard({ action: 'write', text }), context.signal);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const action = { kind: 'resource' };
|
|
79
|
+
return context.fixture('device', device, {
|
|
80
|
+
setNetwork: { ...action, label: (state) => state },
|
|
81
|
+
setAirplaneMode: action,
|
|
82
|
+
setPermission: { ...action, label: (permission) => permission },
|
|
83
|
+
setLocation: action,
|
|
84
|
+
clearLocation: action,
|
|
85
|
+
setAppearance: { ...action, label: (mode) => mode },
|
|
86
|
+
setOrientation: { ...action, label: (orientation) => orientation },
|
|
87
|
+
setBiometrics: action,
|
|
88
|
+
enrollBiometrics: action,
|
|
89
|
+
installApp: { ...action, label: (appPath) => appPath },
|
|
90
|
+
openApp: { ...action, label: (app) => app },
|
|
91
|
+
closeApp: action,
|
|
92
|
+
foregroundApp: action,
|
|
93
|
+
home: action,
|
|
94
|
+
back: action,
|
|
95
|
+
alert: { ...action, label: (value) => value },
|
|
96
|
+
dismissKeyboard: action,
|
|
97
|
+
clipboard: action,
|
|
98
|
+
setClipboard: { ...action, label: (text) => `${text.length} chars` },
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent-device engine for e2e: a mobile body built with the
|
|
3
|
+
* public `defineEngine`, validated by the same rules and graded by the same
|
|
4
|
+
* capabilities as any other engine. Core imports nothing from here; this
|
|
5
|
+
* package imports the contract from `e2e/engine` and contributes the
|
|
6
|
+
* `device` fixture the way the browser engine contributes `web`.
|
|
7
|
+
*/
|
|
8
|
+
import { type EngineHandle } from 'e2e/engine';
|
|
9
|
+
import type { MobileOptions } from './options.ts';
|
|
10
|
+
import { AgentDeviceSurface } from './surface.ts';
|
|
11
|
+
/** Assembles the manifest for one surface. Exported for tests that script the client. */
|
|
12
|
+
export declare function buildEngine(surface: AgentDeviceSurface): EngineHandle;
|
|
13
|
+
/** Creates one agent-device engine: one device session per worker, one fresh app launch per attempt. */
|
|
14
|
+
export declare function mobile(options: MobileOptions): EngineHandle;
|
|
15
|
+
/** The surface behind a handle this package created; undefined for any other engine. */
|
|
16
|
+
export declare function surfaceOf(engine: EngineHandle): AgentDeviceSurface | undefined;
|
|
17
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7F,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,cAAc,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAIlD,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,YAAY,CA+CrE;AAED,wGAAwG;AACxG,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAM3D;AAaD,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,kBAAkB,GAAG,SAAS,CAE9E"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent-device engine for e2e: a mobile body built with the
|
|
3
|
+
* public `defineEngine`, validated by the same rules and graded by the same
|
|
4
|
+
* capabilities as any other engine. Core imports nothing from here; this
|
|
5
|
+
* package imports the contract from `e2e/engine` and contributes the
|
|
6
|
+
* `device` fixture the way the browser engine contributes `web`.
|
|
7
|
+
*/
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { createAgentDeviceClient } from 'agent-device';
|
|
10
|
+
import { defineEngine, obj } from 'e2e/engine';
|
|
11
|
+
import { createDeviceFixture } from './device.js';
|
|
12
|
+
import { DEVICE_ACTIONS, DEVICE_POINTER_ACTIONS } from './actions.js';
|
|
13
|
+
import { AgentDeviceSurface } from './surface.js';
|
|
14
|
+
const surfaces = new WeakMap();
|
|
15
|
+
/** Assembles the manifest for one surface. Exported for tests that script the client. */
|
|
16
|
+
export function buildEngine(surface) {
|
|
17
|
+
const handle = defineEngine({
|
|
18
|
+
name: 'mobile',
|
|
19
|
+
version: ownVersion(),
|
|
20
|
+
spiVersion: 1,
|
|
21
|
+
platform: surface.options.platform,
|
|
22
|
+
...(surface.pool.size === undefined ? {} : { workers: surface.pool.size }),
|
|
23
|
+
prepare: (info) => surface.pool.prepare(info),
|
|
24
|
+
finish: (info) => surface.pool.finish(info),
|
|
25
|
+
init: (info) => surface.init(info),
|
|
26
|
+
startAttempt: (context) => surface.startAttempt(context),
|
|
27
|
+
endAttempt: (context) => surface.endAttempt(context),
|
|
28
|
+
dispose: (context) => surface.dispose(context),
|
|
29
|
+
observe: (operation, options) => surface.observe(operation, options),
|
|
30
|
+
locate: (expression, operation) => surface.locate(expression, operation),
|
|
31
|
+
perform: (ref, action, operation) => surface.perform(ref, action, operation),
|
|
32
|
+
actions: DEVICE_ACTIONS,
|
|
33
|
+
performAt: (point, action, operation) => surface.performAt(point, action, operation),
|
|
34
|
+
pointerActions: DEVICE_POINTER_ACTIONS,
|
|
35
|
+
keyboard: {
|
|
36
|
+
type: (text, keyboardOptions, operation) => surface.typeText(text, keyboardOptions, operation),
|
|
37
|
+
press: (key, operation) => surface.pressFocusedKey(key, operation),
|
|
38
|
+
dismiss: (operation) => surface.dismissKeyboard(operation),
|
|
39
|
+
},
|
|
40
|
+
app: declaredApp(surface.options),
|
|
41
|
+
// No `open`: a device app has no URL to open. Relaunching the pinned app
|
|
42
|
+
// is the device's "recreate the context", so restart and reset need one.
|
|
43
|
+
session: {
|
|
44
|
+
back: (operation) => surface.back(operation),
|
|
45
|
+
...(surface.managesApp
|
|
46
|
+
? {
|
|
47
|
+
restart: (operation) => surface.restart(operation),
|
|
48
|
+
reset: (operation) => surface.reset(operation),
|
|
49
|
+
}
|
|
50
|
+
: {}),
|
|
51
|
+
},
|
|
52
|
+
artifacts: {
|
|
53
|
+
screenshot: (label, operation) => surface.screenshot(label, operation),
|
|
54
|
+
startVideo: (operation) => surface.startVideo(operation),
|
|
55
|
+
stopVideo: (operation) => surface.stopVideo(operation),
|
|
56
|
+
},
|
|
57
|
+
fixtures: {
|
|
58
|
+
device: (context) => createDeviceFixture(surface, context),
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
surfaces.set(handle, surface);
|
|
62
|
+
return handle;
|
|
63
|
+
}
|
|
64
|
+
/** Creates one agent-device engine: one device session per worker, one fresh app launch per attempt. */
|
|
65
|
+
export function mobile(options) {
|
|
66
|
+
const factory = (session, daemon) => createAgentDeviceClient(daemon === undefined ? { session } : obj({ session, daemonBaseUrl: daemon.baseUrl, daemonAuthToken: daemon.authToken }));
|
|
67
|
+
return buildEngine(new AgentDeviceSurface(options, factory));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What the device engine declares about its app: the pinned app (else the
|
|
71
|
+
* build it installs) is the identity cache and session entries key on.
|
|
72
|
+
*/
|
|
73
|
+
function declaredApp(options) {
|
|
74
|
+
return obj({
|
|
75
|
+
identity: options.identity ?? options.app ?? options.appPath,
|
|
76
|
+
environment: options.environment,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** The surface behind a handle this package created; undefined for any other engine. */
|
|
80
|
+
export function surfaceOf(engine) {
|
|
81
|
+
return surfaces.get(engine);
|
|
82
|
+
}
|
|
83
|
+
/** This package's published version, read through require resolution. */
|
|
84
|
+
function ownVersion() {
|
|
85
|
+
try {
|
|
86
|
+
return createRequire(import.meta.url)('../package.json').version;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return 'unknown';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,GAAG,EAAgD,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAoC,CAAC;AAEjE,yFAAyF;AACzF,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,UAAU,EAAE;QACrB,UAAU,EAAE,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;QAClC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1E,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAC3C,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAClC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;QACxD,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;QACpD,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAC9C,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC;QACpE,MAAM,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC;QACxE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC;QAC5E,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;QACpF,cAAc,EAAE,sBAAsB;QACtC,QAAQ,EAAE;YACR,IAAI,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC;YAC9F,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;YAClE,OAAO,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,SAAS,CAAC;SAC3D;QACD,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;QACjC,yEAAyE;QACzE,yEAAyE;QACzE,OAAO,EAAE;YACP,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;YAC5C,GAAG,CAAC,OAAO,CAAC,UAAU;gBACpB,CAAC,CAAC;oBACE,OAAO,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;oBAClD,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;iBAC/C;gBACH,CAAC,CAAC,EAAE,CAAC;SACR;QACD,SAAS,EAAE;YACT,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC;YACtE,UAAU,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;YACxD,SAAS,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC;SACvD;QACD,QAAQ,EAAE;YACR,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;SAC3D;KACF,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,MAAM,CAAC,OAAsB;IAC3C,MAAM,OAAO,GAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CACjD,uBAAuB,CACrB,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CACxH,CAAC;IACJ,OAAO,WAAW,CAAC,IAAI,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAsB;IACzC,OAAO,GAAG,CAAC;QACT,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO;QAC5D,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,SAAS,CAAC,MAAoB;IAC5C,OAAO,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED,yEAAyE;AACzE,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,OAAQ,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation of agent-device failures onto the engine error contract.
|
|
3
|
+
*
|
|
4
|
+
* | agent-device failure | Code |
|
|
5
|
+
* | ----------------------------------------------------------- | ---------------------------- |
|
|
6
|
+
* | already an EngineError / runner error | passed through untouched |
|
|
7
|
+
* | AbortError | CANCELLED |
|
|
8
|
+
* | no active session / session not found | INVALID_STATE |
|
|
9
|
+
* | UNSUPPORTED_OPERATION, NOT_IMPLEMENTED, UNSUPPORTED_PLATFORM | UNSUPPORTED_CAPABILITY |
|
|
10
|
+
* | "not supported on this device" under any code | UNSUPPORTED_CAPABILITY |
|
|
11
|
+
* | a ref the daemon no longer knows (action paths only) | NODE_STALE (retryable) |
|
|
12
|
+
* | timed out | OPERATION_TIMEOUT |
|
|
13
|
+
* | anything else | ENGINE_FAILURE |
|
|
14
|
+
*/
|
|
15
|
+
/** A failure's message in agent-device's normalized form. */
|
|
16
|
+
export declare function message(cause: unknown): string;
|
|
17
|
+
/** Translates an unexpected agent-device error at the contract boundary. */
|
|
18
|
+
export declare function translateError(cause: unknown, operation: string): Error;
|
|
19
|
+
/**
|
|
20
|
+
* Runs one agent-device command under an abort signal and translates its
|
|
21
|
+
* failure onto the engine taxonomy: the one boundary every command crosses.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runCommand<T>(label: string, work: () => Promise<T>, signal: AbortSignal): Promise<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Like translateError, but a ref the daemon no longer binds becomes retryable
|
|
26
|
+
* `NODE_STALE`: nothing was dispatched, so the harness may re-observe and
|
|
27
|
+
* re-resolve the node instead of failing the action.
|
|
28
|
+
*/
|
|
29
|
+
export declare function staleOr(cause: unknown, operation: string): Error;
|
|
30
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiBH,6DAA6D;AAC7D,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE9C;AAqBD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAcvE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAM1G;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAOhE"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation of agent-device failures onto the engine error contract.
|
|
3
|
+
*
|
|
4
|
+
* | agent-device failure | Code |
|
|
5
|
+
* | ----------------------------------------------------------- | ---------------------------- |
|
|
6
|
+
* | already an EngineError / runner error | passed through untouched |
|
|
7
|
+
* | AbortError | CANCELLED |
|
|
8
|
+
* | no active session / session not found | INVALID_STATE |
|
|
9
|
+
* | UNSUPPORTED_OPERATION, NOT_IMPLEMENTED, UNSUPPORTED_PLATFORM | UNSUPPORTED_CAPABILITY |
|
|
10
|
+
* | "not supported on this device" under any code | UNSUPPORTED_CAPABILITY |
|
|
11
|
+
* | a ref the daemon no longer knows (action paths only) | NODE_STALE (retryable) |
|
|
12
|
+
* | timed out | OPERATION_TIMEOUT |
|
|
13
|
+
* | anything else | ENGINE_FAILURE |
|
|
14
|
+
*/
|
|
15
|
+
import { isAgentDeviceError, normalizeAgentDeviceError } from 'agent-device';
|
|
16
|
+
import { EngineError, ConfigurationError, InfrastructureError, TestError, raceAbort } from 'e2e/engine';
|
|
17
|
+
import { cancelled } from './support.js';
|
|
18
|
+
/**
|
|
19
|
+
* True for an error that already carries its classification: an `EngineError`
|
|
20
|
+
* from any module copy, or a runner error. Those cross the boundary untouched;
|
|
21
|
+
* re-wrapping one would turn a `POLICY_DENIED` into an infrastructure failure.
|
|
22
|
+
*/
|
|
23
|
+
function isClassified(cause) {
|
|
24
|
+
if (cause instanceof EngineError || cause instanceof TestError)
|
|
25
|
+
return true;
|
|
26
|
+
if (cause instanceof ConfigurationError || cause instanceof InfrastructureError)
|
|
27
|
+
return true;
|
|
28
|
+
return cause instanceof Error && cause.name === 'EngineError';
|
|
29
|
+
}
|
|
30
|
+
/** A failure's message in agent-device's normalized form. */
|
|
31
|
+
export function message(cause) {
|
|
32
|
+
return normalizeAgentDeviceError(cause).message;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The normalized message followed by the hint the failure itself declared.
|
|
36
|
+
* That hint is the recovery path (press return, tap the app's own Done
|
|
37
|
+
* control) and the model only ever sees the error text, so dropping it leaves
|
|
38
|
+
* the agent retrying the same refused action. The per-code default hint the
|
|
39
|
+
* normalizer would add is CLI advice and stays out.
|
|
40
|
+
*/
|
|
41
|
+
function withHint(cause, text) {
|
|
42
|
+
const hint = isAgentDeviceError(cause) ? cause.details?.hint?.trim() : undefined;
|
|
43
|
+
return hint ? `${text} Hint: ${hint}` : text;
|
|
44
|
+
}
|
|
45
|
+
const NO_SESSION_PATTERN = /no active (?:app )?session|session\b.*\bnot found|open an app first|no app (?:is )?open/i;
|
|
46
|
+
const UNSUPPORTED_CODES = new Set(['UNSUPPORTED_OPERATION', 'NOT_IMPLEMENTED', 'UNSUPPORTED_PLATFORM']);
|
|
47
|
+
const UNSUPPORTED_PATTERN = /\b(?:is )?not supported\b|\bunsupported\b/i;
|
|
48
|
+
const TIMEOUT_PATTERN = /\btimed?\s?out\b/i;
|
|
49
|
+
const STALE_PATTERN = /\bref\b.*\b(?:not found|unknown|stale|no longer|expired|invalid|missing)|\b(?:not found|unknown|stale|no longer|expired|invalid|missing)\b.*\bref\b|refs?generation/i;
|
|
50
|
+
/** Translates an unexpected agent-device error at the contract boundary. */
|
|
51
|
+
export function translateError(cause, operation) {
|
|
52
|
+
if (isClassified(cause))
|
|
53
|
+
return cause;
|
|
54
|
+
if (cause instanceof Error && cause.name === 'AbortError')
|
|
55
|
+
return cancelled(`${operation} cancelled`);
|
|
56
|
+
const normalized = normalizeAgentDeviceError(cause);
|
|
57
|
+
const text = `${operation} failed: ${withHint(cause, normalized.message)}`;
|
|
58
|
+
const options = { retryable: false, cause };
|
|
59
|
+
if (normalized.code === 'SESSION_NOT_FOUND' || NO_SESSION_PATTERN.test(normalized.message)) {
|
|
60
|
+
return new EngineError('INVALID_STATE', text, options);
|
|
61
|
+
}
|
|
62
|
+
if (UNSUPPORTED_CODES.has(normalized.code) || UNSUPPORTED_PATTERN.test(normalized.message)) {
|
|
63
|
+
return new EngineError('UNSUPPORTED_CAPABILITY', text, options);
|
|
64
|
+
}
|
|
65
|
+
if (TIMEOUT_PATTERN.test(normalized.message))
|
|
66
|
+
return new EngineError('OPERATION_TIMEOUT', text, options);
|
|
67
|
+
return new EngineError('ENGINE_FAILURE', text, options);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Runs one agent-device command under an abort signal and translates its
|
|
71
|
+
* failure onto the engine taxonomy: the one boundary every command crosses.
|
|
72
|
+
*/
|
|
73
|
+
export async function runCommand(label, work, signal) {
|
|
74
|
+
try {
|
|
75
|
+
return await raceAbort(work, signal, label);
|
|
76
|
+
}
|
|
77
|
+
catch (cause) {
|
|
78
|
+
throw translateError(cause, label);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Like translateError, but a ref the daemon no longer binds becomes retryable
|
|
83
|
+
* `NODE_STALE`: nothing was dispatched, so the harness may re-observe and
|
|
84
|
+
* re-resolve the node instead of failing the action.
|
|
85
|
+
*/
|
|
86
|
+
export function staleOr(cause, operation) {
|
|
87
|
+
if (isClassified(cause))
|
|
88
|
+
return cause;
|
|
89
|
+
const normalized = normalizeAgentDeviceError(cause);
|
|
90
|
+
if (STALE_PATTERN.test(normalized.message)) {
|
|
91
|
+
return new EngineError('NODE_STALE', `${operation}: ${normalized.message}`, { retryable: true, cause });
|
|
92
|
+
}
|
|
93
|
+
return translateError(cause, operation);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@e2edev/mobile` public surface: the `mobile()` engine factory,
|
|
3
|
+
* the `device` fixture types, and a `test` typed with that fixture. `expect`
|
|
4
|
+
* and `credentials` still come from `e2e`; the agent-side tool pack lives on
|
|
5
|
+
* the `@e2edev/mobile/tools` subpath so this entry never loads the AI SDK.
|
|
6
|
+
*/
|
|
7
|
+
import type { Device } from './device.ts';
|
|
8
|
+
export { mobile } from './engine.ts';
|
|
9
|
+
export type { MobileOptions, MobilePlatform } from './options.ts';
|
|
10
|
+
export type { DeviceDaemon } from './bindings.ts';
|
|
11
|
+
export type { DeviceLease, DeviceProvider, DeviceReleaseContext, DeviceRequest } from './provider.ts';
|
|
12
|
+
export type { InstallAppOptions, InstalledApp } from './surface.ts';
|
|
13
|
+
export type { BiometricSensor, Device, DeviceOrientation, DevicePermission, ForegroundApp } from './device.ts';
|
|
14
|
+
/**
|
|
15
|
+
* `test` typed with this engine's contributed `device` fixture. The same
|
|
16
|
+
* runtime `test` as `e2e`'s; only the fixture types differ.
|
|
17
|
+
*/
|
|
18
|
+
export declare const test: import("e2e").TestAPI<import("e2e").TestFixtures & {
|
|
19
|
+
device: Device;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACtG,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACpE,YAAY,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/G;;;GAGG;AACH,eAAO,MAAM,IAAI;YAAyB,MAAM;EAAK,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@e2edev/mobile` public surface: the `mobile()` engine factory,
|
|
3
|
+
* the `device` fixture types, and a `test` typed with that fixture. `expect`
|
|
4
|
+
* and `credentials` still come from `e2e`; the agent-side tool pack lives on
|
|
5
|
+
* the `@e2edev/mobile/tools` subpath so this entry never loads the AI SDK.
|
|
6
|
+
*/
|
|
7
|
+
import { test as base } from 'e2e';
|
|
8
|
+
export { mobile } from './engine.js';
|
|
9
|
+
/**
|
|
10
|
+
* `test` typed with this engine's contributed `device` fixture. The same
|
|
11
|
+
* runtime `test` as `e2e`'s; only the fixture types differ.
|
|
12
|
+
*/
|
|
13
|
+
export const test = base.extend();
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,MAAM,KAAK,CAAC;AAGnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOrC;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAsB,CAAC"}
|
package/dist/locate.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocatorExpression evaluation over one projected snapshot: the location
|
|
3
|
+
* capability's query language answered against the accessibility tree the
|
|
4
|
+
* device just reported. One immediate pass, every match in document order;
|
|
5
|
+
* polling, strictness, and staleness stay with the runner.
|
|
6
|
+
*/
|
|
7
|
+
import { type LocatorExpression } from 'e2e/engine';
|
|
8
|
+
import { type ProjectedNode } from './nodes.ts';
|
|
9
|
+
/** Resolves one expression to the nodes it currently matches. */
|
|
10
|
+
export declare function resolveExpression(expression: LocatorExpression, index: readonly ProjectedNode[]): ProjectedNode[];
|
|
11
|
+
//# sourceMappingURL=locate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../src/locate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA4B,KAAK,iBAAiB,EAAsB,MAAM,YAAY,CAAC;AAClG,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,EAAE,CAiCjH"}
|
package/dist/locate.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocatorExpression evaluation over one projected snapshot: the location
|
|
3
|
+
* capability's query language answered against the accessibility tree the
|
|
4
|
+
* device just reported. One immediate pass, every match in document order;
|
|
5
|
+
* polling, strictness, and staleness stay with the runner.
|
|
6
|
+
*/
|
|
7
|
+
import { EngineError, matchesText } from 'e2e/engine';
|
|
8
|
+
import { isWithin } from './nodes.js';
|
|
9
|
+
import { compileSelector } from './selector.js';
|
|
10
|
+
/** Resolves one expression to the nodes it currently matches. */
|
|
11
|
+
export function resolveExpression(expression, index) {
|
|
12
|
+
switch (expression.kind) {
|
|
13
|
+
case 'query': {
|
|
14
|
+
const candidates = expression.scope === undefined ? index : descendantsOf(resolveExpression(expression.scope, index), index);
|
|
15
|
+
const matches = candidates.filter((entry) => matchesQuery(entry, expression.query));
|
|
16
|
+
return expression.query.kind === 'text' ? innermostOnly(matches) : matches;
|
|
17
|
+
}
|
|
18
|
+
case 'filter': {
|
|
19
|
+
const source = resolveExpression(expression.source, index);
|
|
20
|
+
return source.filter((entry) => {
|
|
21
|
+
if (expression.hasText !== undefined && !subtreeHasText(entry, index, expression.hasText))
|
|
22
|
+
return false;
|
|
23
|
+
if (expression.has !== undefined) {
|
|
24
|
+
const within = descendantsOf([entry], index);
|
|
25
|
+
if (resolveExpression(expression.has, within).length === 0)
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
case 'index': {
|
|
32
|
+
const source = resolveExpression(expression.source, index);
|
|
33
|
+
const position = expression.index === 'first' ? 0 : expression.index === 'last' ? source.length - 1 : expression.index;
|
|
34
|
+
const picked = source[position];
|
|
35
|
+
return picked === undefined ? [] : [picked];
|
|
36
|
+
}
|
|
37
|
+
case 'selector':
|
|
38
|
+
return compileSelector(expression.selector)(index);
|
|
39
|
+
case 'frame':
|
|
40
|
+
throw new EngineError('FRAME_NOT_FOUND', 'a device surface has no nested documents to scope a query into', {
|
|
41
|
+
retryable: false,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Drops every match that contains another match, the way a browser's text
|
|
47
|
+
* selector answers with the innermost element. A device tree echoes text
|
|
48
|
+
* upwards: iOS reports a React Native Text host view and its StaticText child
|
|
49
|
+
* with the same label, and a container view inherits its descendants' labels,
|
|
50
|
+
* so without this rule every `getByText` on such a screen is ambiguous.
|
|
51
|
+
*/
|
|
52
|
+
function innermostOnly(matches) {
|
|
53
|
+
return matches.filter((entry) => !matches.some((other) => other !== entry && isWithin(other, entry)));
|
|
54
|
+
}
|
|
55
|
+
/** Strict descendants of any node in `ancestors`, in document order. */
|
|
56
|
+
function descendantsOf(ancestors, index) {
|
|
57
|
+
if (ancestors.length === 0)
|
|
58
|
+
return [];
|
|
59
|
+
return index.filter((entry) => ancestors.some((ancestor) => isWithin(entry, ancestor)));
|
|
60
|
+
}
|
|
61
|
+
function subtreeHasText(entry, index, pattern) {
|
|
62
|
+
const ownTexts = [entry.node.name, entry.node.text, entry.node.value];
|
|
63
|
+
if (ownTexts.some((text) => text !== undefined && matchesText(text, pattern)))
|
|
64
|
+
return true;
|
|
65
|
+
return descendantsOf([entry], index).some((child) => [child.node.name, child.node.text, child.node.value].some((text) => text !== undefined && matchesText(text, pattern)));
|
|
66
|
+
}
|
|
67
|
+
const STATE_KEYS = ['checked', 'disabled', 'selected', 'expanded', 'pressed'];
|
|
68
|
+
/**
|
|
69
|
+
* One node against one semantic query. Role queries skip hidden nodes, as a
|
|
70
|
+
* browser's role query does; the other kinds
|
|
71
|
+
* answer with every node and leave visibility to the action or assertion,
|
|
72
|
+
* unless the query says `visible`, which drops hidden nodes for every kind.
|
|
73
|
+
*/
|
|
74
|
+
function matchesQuery(entry, query) {
|
|
75
|
+
const node = entry.node;
|
|
76
|
+
if (query.visible === true && node.states?.hidden === true)
|
|
77
|
+
return false;
|
|
78
|
+
switch (query.kind) {
|
|
79
|
+
case 'role': {
|
|
80
|
+
if (query.value.kind !== 'string') {
|
|
81
|
+
throw new EngineError('ENGINE_FAILURE', 'role query value must be a string', { retryable: false });
|
|
82
|
+
}
|
|
83
|
+
if ((node.role ?? '') !== query.value.value)
|
|
84
|
+
return false;
|
|
85
|
+
if (query.name !== undefined && !matchesText(node.name ?? '', query.name))
|
|
86
|
+
return false;
|
|
87
|
+
if (node.states?.hidden === true)
|
|
88
|
+
return false;
|
|
89
|
+
const wanted = query.states ?? {};
|
|
90
|
+
for (const key of STATE_KEYS) {
|
|
91
|
+
const expected = wanted[key];
|
|
92
|
+
if (expected !== undefined && (node.states?.[key] ?? false) !== expected)
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// A device tree reports no heading levels, so a level query matches nothing rather than everything.
|
|
96
|
+
if (query.level !== undefined && node.level !== query.level)
|
|
97
|
+
return false;
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
case 'label':
|
|
101
|
+
return node.name !== undefined && matchesText(node.name, query.value);
|
|
102
|
+
case 'placeholder': {
|
|
103
|
+
const placeholder = node.attributes?.['placeholder'];
|
|
104
|
+
return placeholder !== undefined && matchesText(placeholder, query.value);
|
|
105
|
+
}
|
|
106
|
+
case 'text':
|
|
107
|
+
return ((node.name !== undefined && matchesText(node.name, query.value)) ||
|
|
108
|
+
(node.text !== undefined && matchesText(node.text, query.value)));
|
|
109
|
+
case 'displayValue':
|
|
110
|
+
return node.value !== undefined && matchesText(node.value, query.value);
|
|
111
|
+
case 'testId':
|
|
112
|
+
return node.testId !== undefined && matchesText(node.testId, query.value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=locate.js.map
|