@astur-mobile/core 0.5.0-beta.5 → 0.7.0-beta

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/session.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Coordinates, DeviceFileEntry, DeviceInfo, DeviceOrientation, DoctorCheck, DragGesture, DoubleTapOptions, ElementDragOptions, ElementDragTarget, ElementDoubleTapOptions, ElementFillOptions, ElementLongPressOptions, ElementSelector, ElementTapOptions, ElementWaitOptions, LaunchOptions, LongPressOptions, KeyboardState, MobileContextInfo, NetworkCapabilities, NetworkRedactionOptions, NetworkRequestFilter, NetworkRequestRecord, MobileElementSnapshot, MobileRole, NormalizedCapabilities, PlatformName, InspectorSession, LocatorSuggestion, RecordingStopOptions, RoleSelectorOptions, ScreenshotOptions, SwipeGesture, TapOptions, UiTreeSubscribeOptions, UiTreeUpdate, AsturConfig, AppResetOptions, AppUnderTest, Bounds, WebViewEndpoint, WebViewSelector } from '@astur-mobile/protocol';
1
+ import type { AppResetOptions, AppUnderTest, AsturConfig, Bounds, BrowserCapabilities, Coordinates, DeviceFileEntry, DeviceInfo, DeviceOrientation, DeviceSelector, DoctorCheck, DoubleTapOptions, DragGesture, ElementDoubleTapOptions, ElementDragOptions, ElementDragTarget, ElementFillOptions, ElementLongPressOptions, ElementSelector, ElementTapOptions, ElementWaitOptions, ForegroundApp, InspectorSession, InstalledApp, KeyboardState, LaunchOptions, LocatorSuggestion, LongPressOptions, MobileContextInfo, MobileElementSnapshot, MobileRole, NetworkCapabilities, NetworkRedactionOptions, NetworkRequestFilter, NetworkRequestRecord, NormalizedCapabilities, PlatformName, RecordingStopOptions, RoleSelectorOptions, ScreenshotOptions, SwipeGesture, TapOptions, UiTreeSubscribeOptions, UiTreeUpdate, WebViewEndpoint, WebViewSelector } from '@astur-mobile/protocol';
2
2
  import { type RuntimeInspectorSessionOptions } from './inspector.js';
3
3
  import { MobileLocator } from './locator.js';
4
4
  import { WebContext, type WebEvaluator } from './webBridge.js';
@@ -16,6 +16,11 @@ export interface PlatformDriver {
16
16
  readonly platform: PlatformName;
17
17
  doctor(): Promise<DoctorCheck[]>;
18
18
  listDevices(): Promise<DeviceInfo[]>;
19
+ /**
20
+ * The device `createSession` would open for `selector` right now, found
21
+ * without touching it; `undefined` when none qualifies yet.
22
+ */
23
+ findDevice?(selector: DeviceSelector): Promise<DeviceInfo | undefined>;
19
24
  createSession(capabilities: NormalizedCapabilities): Promise<PlatformSession>;
20
25
  }
21
26
  export interface PlatformSession {
@@ -23,6 +28,12 @@ export interface PlatformSession {
23
28
  readonly deviceInfo: DeviceInfo;
24
29
  close(): Promise<void>;
25
30
  isAppInstalled?(identifier: string): Promise<boolean>;
31
+ /**
32
+ * Whether the installed `identifier` is exactly the build at `path`:
33
+ * `false` when it differs or is absent, `undefined` when that cannot be
34
+ * established. Callers must treat `undefined` as "reinstall".
35
+ */
36
+ isInstalledAppCurrent?(identifier: string, path: string): Promise<boolean | undefined>;
26
37
  installApp(path: string): Promise<void>;
27
38
  uninstallApp(identifier: string): Promise<void>;
28
39
  launchApp(options?: LaunchOptions): Promise<void>;
@@ -33,6 +44,11 @@ export interface PlatformSession {
33
44
  revokePermission?(identifier: string, permission: string): Promise<void>;
34
45
  resetApp(options?: AppResetOptions): Promise<void>;
35
46
  setOrientation?(orientation: DeviceOrientation): Promise<void>;
47
+ getOrientation?(): Promise<DeviceOrientation>;
48
+ listApps?(options?: {
49
+ system?: boolean;
50
+ }): Promise<InstalledApp[]>;
51
+ getForegroundApp?(): Promise<ForegroundApp | undefined>;
36
52
  lockDevice(): Promise<void>;
37
53
  unlockDevice(): Promise<void>;
38
54
  isDeviceLocked(): Promise<boolean>;
@@ -62,7 +78,31 @@ export interface PlatformSession {
62
78
  startRecording?(): Promise<void>;
63
79
  stopRecording?(options?: RecordingStopOptions): Promise<Buffer | undefined>;
64
80
  screenshot(): Promise<Buffer>;
81
+ /**
82
+ * Hands a URL to the OS. Deliberately not browser-specific — a deep link into
83
+ * the app under test goes through here too, which is why it stays `void` and
84
+ * does not try to find a page afterwards.
85
+ */
65
86
  openWeb(url: string): Promise<void>;
87
+ /**
88
+ * Launches the configured browser at a URL, rather than letting the OS pick a
89
+ * handler. Drivers that cannot target a browser omit this, and
90
+ * {@link AsturDevice.browser} reports it as unsupported.
91
+ */
92
+ openBrowser?(url: string): Promise<void>;
93
+ /** What this session can do with a browser, detected at runtime. */
94
+ getBrowserCapabilities?(): Promise<BrowserCapabilities>;
95
+ /**
96
+ * Opens a **new** browser tab and returns its target id.
97
+ *
98
+ * Optional because tab lifecycle is not universal: Chrome exposes it over the
99
+ * debugging socket, WebKit's remote inspector does not. A driver that omits
100
+ * these falls back to reusing one tab, which is weaker isolation but the only
101
+ * thing the platform allows.
102
+ */
103
+ openBrowserTab?(url: string): Promise<string | undefined>;
104
+ /** Closes a browser tab by target id. */
105
+ closeBrowserTab?(id: string): Promise<void>;
66
106
  pushFile?(localPath: string, remotePath: string): Promise<void>;
67
107
  pullFile?(remotePath: string): Promise<Buffer>;
68
108
  saveFile?(remotePath: string, localPath: string): Promise<void>;
@@ -108,6 +148,21 @@ export declare class AsturDevice {
108
148
  clearData: (target?: string | AppUnderTest) => Promise<void>;
109
149
  clearCache: (target?: string | AppUnderTest) => Promise<void>;
110
150
  reset: (options?: AppResetOptions) => Promise<void>;
151
+ /**
152
+ * Apps installed on the device.
153
+ *
154
+ * Third-party apps only by default: a full system listing runs to hundreds
155
+ * of entries and buries the one being tested. Pass `{ system: true }` when
156
+ * a test genuinely needs to assert on a built-in app.
157
+ */
158
+ list: (options?: {
159
+ system?: boolean;
160
+ }) => Promise<InstalledApp[]>;
161
+ /**
162
+ * The app in the foreground right now, or `undefined` when the device is
163
+ * showing the launcher or a system surface rather than an app.
164
+ */
165
+ foreground: () => Promise<ForegroundApp | undefined>;
111
166
  };
112
167
  readonly gestures: {
113
168
  tap: (point: Coordinates, options?: TapOptions) => Promise<void>;
@@ -123,6 +178,8 @@ export declare class AsturDevice {
123
178
  recentApps: () => Promise<void>;
124
179
  };
125
180
  readonly orientation: {
181
+ /** The device's current orientation. */
182
+ get: () => Promise<DeviceOrientation>;
126
183
  set: (orientation: DeviceOrientation) => Promise<void>;
127
184
  portrait: () => Promise<void>;
128
185
  landscape: () => Promise<void>;
@@ -161,6 +218,62 @@ export declare class AsturDevice {
161
218
  */
162
219
  clear: () => Promise<void>;
163
220
  };
221
+ /**
222
+ * The page currently open in the browser, if one has been opened.
223
+ *
224
+ * Held so navigation can dispose it before re-resolving, and so a suite that
225
+ * forgets to close is still cleaned up when the session ends.
226
+ */
227
+ private browserPage?;
228
+ /** Target id of the tab this session opened, when it opened one itself. */
229
+ private browserTabId?;
230
+ /**
231
+ * Drives a **browser** rather than the app under test — for testing a mobile
232
+ * web page on the same real device or emulator the native suite runs on.
233
+ *
234
+ * Everything below the page is the existing WebView machinery: once a tab is
235
+ * inspectable, the same injected-JS bridge drives it. What this adds is the
236
+ * target and navigation, which an in-app WebView never needed.
237
+ *
238
+ * Ask {@link browser.capabilities} before using it, the same way
239
+ * {@link network.capabilities} is asked, so a spec stays portable.
240
+ */
241
+ readonly browser: {
242
+ /** What this session can do with a browser. Never throws. */
243
+ capabilities: () => Promise<BrowserCapabilities>;
244
+ /**
245
+ * Launches the browser at `url` and returns a context on the page.
246
+ *
247
+ * The returned context is the handle to use until the next navigation —
248
+ * each navigation re-resolves the page and returns a fresh one.
249
+ */
250
+ open: (url: string, options?: {
251
+ timeout?: number;
252
+ }) => Promise<WebContext>;
253
+ /** Navigates the open page and returns it, now showing `url`. */
254
+ navigate: (url: string, options?: {
255
+ timeout?: number;
256
+ }) => Promise<WebContext>;
257
+ reload: (options?: {
258
+ timeout?: number;
259
+ }) => Promise<WebContext>;
260
+ back: (options?: {
261
+ timeout?: number;
262
+ }) => Promise<WebContext>;
263
+ forward: (options?: {
264
+ timeout?: number;
265
+ }) => Promise<WebContext>;
266
+ /** The open page's current URL. */
267
+ url: () => Promise<string>;
268
+ /**
269
+ * Closes the page, and its tab where the platform allows it. The browser
270
+ * itself is left running — starting it again per test costs seconds.
271
+ *
272
+ * The Astur fixture calls this after every test, so tabs cannot accumulate
273
+ * and no test inherits the previous one's page.
274
+ */
275
+ close: () => Promise<void>;
276
+ };
164
277
  readonly keyboard: {
165
278
  isVisible: () => Promise<boolean>;
166
279
  dismiss: () => Promise<void>;
@@ -219,12 +332,16 @@ export declare class AsturDevice {
219
332
  getByType(value: string, options?: {
220
333
  exact?: boolean;
221
334
  }): MobileLocator;
335
+ getByPlaceholder(value: string, options?: {
336
+ exact?: boolean;
337
+ }): MobileLocator;
222
338
  inspector(options?: RuntimeInspectorSessionOptions): InspectorSession;
223
339
  suggestLocators(selector: ElementSelector): Promise<LocatorSuggestion[]>;
224
340
  tap(point: Coordinates, options?: TapOptions): Promise<void>;
225
341
  doubleTap(point: Coordinates, options?: DoubleTapOptions): Promise<void>;
226
342
  longPress(point: Coordinates, options?: LongPressOptions): Promise<void>;
227
343
  pressAndHold(point: Coordinates, options?: LongPressOptions): Promise<void>;
344
+ getOrientation(): Promise<DeviceOrientation>;
228
345
  setOrientation(orientation: DeviceOrientation): Promise<void>;
229
346
  pressKey(key: string): Promise<void>;
230
347
  back(): Promise<void>;
@@ -253,6 +370,33 @@ export declare class AsturDevice {
253
370
  * frameworks (Flutter, React Native) on each platform that exposes the transport.
254
371
  */
255
372
  webContext(selector?: WebViewSelector): Promise<WebContext>;
373
+ /**
374
+ * Re-resolves the page after a history navigation.
375
+ *
376
+ * No URL to match on here — where `back()` lands is exactly what the test is
377
+ * asking about — so this takes whichever page the browser now shows.
378
+ */
379
+ /**
380
+ * Runs a history navigation on the attached tab and waits for it to settle.
381
+ *
382
+ * Deliberately stays on the same target rather than re-resolving. A browser
383
+ * keeps every tab a suite has opened, several on the same URL, so "find the
384
+ * page again" is ambiguous in a way it never is for an app's single WebView —
385
+ * and picking wrong silently drives a frozen background tab. Chromium keeps
386
+ * one target across a same-tab navigation; if the transport does die, the
387
+ * re-resolve below is the fallback rather than the norm.
388
+ */
389
+ private renavigate;
390
+ /**
391
+ * Brings the attached tab to `url`, navigating only if it is not already
392
+ * there — so an intent that happened to land correctly costs nothing.
393
+ */
394
+ private ensureAt;
395
+ /** Attaches to an already-open page, or resolves undefined. Never throws. */
396
+ private tryResolveBrowserPage;
397
+ private resolveBrowserPage;
398
+ private requireBrowserPage;
399
+ private closeBrowserPage;
256
400
  close(): Promise<void>;
257
401
  }
258
402
  export declare class AsturRuntime {
@@ -260,6 +404,11 @@ export declare class AsturRuntime {
260
404
  register(driver: PlatformDriver): this;
261
405
  doctor(): Promise<DoctorCheck[]>;
262
406
  listDevices(platform?: PlatformName): Promise<DeviceInfo[]>;
407
+ /**
408
+ * The device `createDevice(config)` would open, found without touching it.
409
+ * Reservation locks this, so two spellings of one device collide.
410
+ */
411
+ findDevice(config: AsturConfig): Promise<DeviceInfo | undefined>;
263
412
  createDevice(config: AsturConfig): Promise<AsturDevice>;
264
413
  private requireDriver;
265
414
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,YAAY,EACZ,MAAM,EACN,eAAe,EACf,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAA0B,KAAK,8BAA8B,EAAE,MAAM,gBAAgB,CAAC;AAE7F,OAAO,EAA6C,aAAa,EAAiB,MAAM,cAAc,CAAC;AACvG,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG/D,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACjC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACrC,aAAa,CAAC,YAAY,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,cAAc,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,SAAS,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,eAAe,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,gBAAgB,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,cAAc,CAAC,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC1C,WAAW,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC;IACzE,gBAAgB,CAAC,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,cAAc,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,CAAC,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC;IACpF,YAAY,CAAC,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC3E,gBAAgB,CAAC,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAClF,cAAc,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACzG,oBAAoB,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,UAAU,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,gBAAgB,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/F,gBAAgB,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/F,WAAW,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpG,WAAW,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChH,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5E,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,QAAQ,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,QAAQ,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,UAAU,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3D,gBAAgB,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5C,eAAe,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC;;;;;OAKG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACxD,kBAAkB,CAAC,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACxF,oBAAoB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,YAAY,CAAC,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC9C,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACtE;;;;;OAKG;IACH,kBAAkB,CAAC,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACxE;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;gBAE9B,OAAO,EAAE,eAAe;IAMpC,QAAQ,CAAC,GAAG;yBACa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;6BASlB,MAAM,GAAG,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;2BAIvC,aAAa,KAAG,OAAO,CAAC,IAAI,CAAC;yBAIjC,OAAO,CAAC,IAAI,CAAC;6BAIP,MAAM,GAAG,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;8BAIpC,MAAM,GAAG,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;0BAIzC,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC;MAGvD;IAEF,QAAQ,CAAC,QAAQ;qBACI,WAAW,YAAY,UAAU,KAAG,OAAO,CAAC,IAAI,CAAC;2BAI3C,WAAW,YAAY,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAAC;2BAIvD,WAAW,YAAY,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAAC;8BAIpD,WAAW,YAAY,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAAC;yBAI5D,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;wBAI7B,WAAW,KAAG,OAAO,CAAC,IAAI,CAAC;MAGjD;IAEF,QAAQ,CAAC,UAAU;oBACD,OAAO,CAAC,IAAI,CAAC;oBAIb,OAAO,CAAC,IAAI,CAAC;0BAIP,OAAO,CAAC,IAAI,CAAC;MAGnC;IAEF,QAAQ,CAAC,WAAW;2BACO,iBAAiB,KAAG,OAAO,CAAC,IAAI,CAAC;wBAItC,OAAO,CAAC,IAAI,CAAC;yBAIZ,OAAO,CAAC,IAAI,CAAC;MAGlC;IAEF,QAAQ,CAAC,MAAM;oBACG,OAAO,CAAC,IAAI,CAAC;sBAIX,OAAO,CAAC,IAAI,CAAC;wBAIX,OAAO,CAAC,OAAO,CAAC;MACpC;IAEF,QAAQ,CAAC,WAAW;4BACQ,MAAM,WAAW,MAAM,GAAG,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;6BAQrD,MAAM,WAAW,MAAM,GAAG,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;MAOjF;IAEF;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO;4BACU,OAAO,CAAC,mBAAmB,CAAC;QAepD;;;;WAIG;4BAEQ,oBAAoB,YACnB,uBAAuB,KAChC,OAAO,CAAC,oBAAoB,EAAE,CAAC;QAalC;;;;WAIG;qBACc,OAAO,CAAC,IAAI,CAAC;MAG9B;IAEF,QAAQ,CAAC,QAAQ;yBACM,OAAO,CAAC,OAAO,CAAC;uBAQlB,OAAO,CAAC,IAAI,CAAC;oBAWhB,OAAO,CAAC,IAAI,CAAC;QAI7B;;;;;;;;;;;;;;;;;;;;WAoBG;qBACgB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;wBAWnB,aAAa,GAAG,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC;MAmBrE;IAEF,QAAQ,CAAC,KAAK;0BACY,MAAM,cAAc,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAQzC,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;2BAQxB,MAAM,aAAa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;6BAavC,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAQxB,MAAM,KAAG,OAAO,CAAC,eAAe,EAAE,CAAC;MAO5D;IAEF,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,aAAa;IAIxC,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAIpE,QAAQ,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAS9E,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,aAAa;IAIjD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAIvE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAItE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAItE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAIxE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAIpE,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,aAAa;IAIlF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAItE,SAAS,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,gBAAgB;IAI/D,eAAe,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAIxE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5E,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxE,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,cAAc,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,UAAU,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,MAAM,CAAC;IAUvE,8EAA8E;IACxE,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAIhC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAQ9E,IAAI,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAItC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ3B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,QAAQ,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAWxC,eAAe,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAW3E;;;;;OAKG;IACG,UAAU,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAW3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAmCD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAEnE,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAKhC,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAKhC,WAAW,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAM3D,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAkC7D,OAAO,CAAC,aAAa;CAQtB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,oBAAoB,EAAE,CAoBxB"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
package/dist/session.js CHANGED
@@ -6,6 +6,7 @@ import { createInspectorSession } from './inspector.js';
6
6
  import { preparePointerTargetForKeyboard } from './keyboard.js';
7
7
  import { by, captureMaskedScreenshot, findElements, MobileLocator, screenshotKey } from './locator.js';
8
8
  import { WebContext } from './webBridge.js';
9
+ import { browserUnsupported, connectBrowserPage, currentUrl, markNavigation, pageMatcher, runNavigation, settlePage, waitForLoad, DEFAULT_PAGE_TIMEOUT_MS, REUSE_PROBE_MS } from './browser.js';
9
10
  import { delay } from './wait.js';
10
11
  export class AsturDevice {
11
12
  capabilities;
@@ -41,6 +42,29 @@ export class AsturDevice {
41
42
  },
42
43
  reset: async (options) => {
43
44
  await this.session.resetApp(options);
45
+ },
46
+ /**
47
+ * Apps installed on the device.
48
+ *
49
+ * Third-party apps only by default: a full system listing runs to hundreds
50
+ * of entries and buries the one being tested. Pass `{ system: true }` when
51
+ * a test genuinely needs to assert on a built-in app.
52
+ */
53
+ list: async (options) => {
54
+ if (!this.session.listApps) {
55
+ throw new AsturError('APP_LIST_UNSUPPORTED', 'This platform session cannot list installed apps.');
56
+ }
57
+ return this.session.listApps(options);
58
+ },
59
+ /**
60
+ * The app in the foreground right now, or `undefined` when the device is
61
+ * showing the launcher or a system surface rather than an app.
62
+ */
63
+ foreground: async () => {
64
+ if (!this.session.getForegroundApp) {
65
+ throw new AsturError('FOREGROUND_APP_UNSUPPORTED', 'This platform session cannot report the foreground app.');
66
+ }
67
+ return this.session.getForegroundApp();
44
68
  }
45
69
  };
46
70
  gestures = {
@@ -75,6 +99,13 @@ export class AsturDevice {
75
99
  }
76
100
  };
77
101
  orientation = {
102
+ /** The device's current orientation. */
103
+ get: async () => {
104
+ if (!this.session.getOrientation) {
105
+ throw new AsturError('ORIENTATION_READ_UNSUPPORTED', 'This platform session cannot report the current orientation.');
106
+ }
107
+ return this.session.getOrientation();
108
+ },
78
109
  set: async (orientation) => {
79
110
  await this.setOrientation(orientation);
80
111
  },
@@ -154,6 +185,113 @@ export class AsturDevice {
154
185
  await this.session.clearNetworkRequests?.();
155
186
  }
156
187
  };
188
+ /**
189
+ * The page currently open in the browser, if one has been opened.
190
+ *
191
+ * Held so navigation can dispose it before re-resolving, and so a suite that
192
+ * forgets to close is still cleaned up when the session ends.
193
+ */
194
+ browserPage;
195
+ /** Target id of the tab this session opened, when it opened one itself. */
196
+ browserTabId;
197
+ /**
198
+ * Drives a **browser** rather than the app under test — for testing a mobile
199
+ * web page on the same real device or emulator the native suite runs on.
200
+ *
201
+ * Everything below the page is the existing WebView machinery: once a tab is
202
+ * inspectable, the same injected-JS bridge drives it. What this adds is the
203
+ * target and navigation, which an in-app WebView never needed.
204
+ *
205
+ * Ask {@link browser.capabilities} before using it, the same way
206
+ * {@link network.capabilities} is asked, so a spec stays portable.
207
+ */
208
+ browser = {
209
+ /** What this session can do with a browser. Never throws. */
210
+ capabilities: async () => {
211
+ if (!this.session.getBrowserCapabilities || !this.session.openBrowser) {
212
+ return browserUnsupported(this.deviceInfo.platform, 'this driver has no browser target');
213
+ }
214
+ return this.session.getBrowserCapabilities();
215
+ },
216
+ /**
217
+ * Launches the browser at `url` and returns a context on the page.
218
+ *
219
+ * The returned context is the handle to use until the next navigation —
220
+ * each navigation re-resolves the page and returns a fresh one.
221
+ */
222
+ open: async (url, options) => {
223
+ const capabilities = await this.browser.capabilities();
224
+ if (!capabilities.supported || !this.session.openBrowser) {
225
+ throw new AsturError('BROWSER_NOT_SUPPORTED', capabilities.coverage);
226
+ }
227
+ await this.browser.close();
228
+ // Prefer a genuinely fresh tab, the way Playwright hands each test a new
229
+ // page. Chrome supports it over the debugging socket; WebKit's inspector
230
+ // does not, so iOS falls back to reusing one tab and reloading it.
231
+ if (this.session.openBrowserTab) {
232
+ const id = await this.session.openBrowserTab(url).catch(() => undefined);
233
+ if (id) {
234
+ this.browserTabId = id;
235
+ // Attach to the new tab without filtering on the URL. A tab created
236
+ // over the debugging socket starts at about:blank and only reaches the
237
+ // requested URL once it has loaded, so matching on the URL here waits
238
+ // out the whole budget before falling back. `ensureAt` drives it there
239
+ // in-page, which is both faster and the same code path as navigate().
240
+ const opened = await this.resolveBrowserPage(undefined, options?.timeout);
241
+ return this.ensureAt(opened, url, options?.timeout);
242
+ }
243
+ }
244
+ // Fallback: reuse whatever tab is open rather than firing the launch
245
+ // intent again. Each intent leaves another tab behind, so a suite that
246
+ // opens a page per test would climb to dozens and eventually attach to
247
+ // none of them.
248
+ const existing = await this.tryResolveBrowserPage(REUSE_PROBE_MS);
249
+ if (existing) {
250
+ return this.ensureAt(existing, url, options?.timeout);
251
+ }
252
+ // Nothing attachable: start the browser. The launch is not trusted to land
253
+ // on the URL, because Chrome dedupes a VIEW intent against an open tab and
254
+ // simply focuses it.
255
+ await this.session.openBrowser(url);
256
+ const page = await this.resolveBrowserPage(undefined, options?.timeout);
257
+ return this.ensureAt(page, url, options?.timeout);
258
+ },
259
+ /** Navigates the open page and returns it, now showing `url`. */
260
+ navigate: async (url, options) => {
261
+ return this.ensureAt(this.requireBrowserPage(), url, options?.timeout);
262
+ },
263
+ reload: async (options) => {
264
+ // Reload must come back to the same page, so reattach by URL rather than
265
+ // taking whichever tab answers first.
266
+ const current = await this.browser.url().catch(() => undefined);
267
+ return this.renavigate('location.reload()', options?.timeout, current);
268
+ },
269
+ back: async (options) => {
270
+ return this.renavigate('history.back()', options?.timeout);
271
+ },
272
+ forward: async (options) => {
273
+ return this.renavigate('history.forward()', options?.timeout);
274
+ },
275
+ /** The open page's current URL. */
276
+ url: async () => {
277
+ return String(await this.requireBrowserPage().evaluate('location.href') ?? '');
278
+ },
279
+ /**
280
+ * Closes the page, and its tab where the platform allows it. The browser
281
+ * itself is left running — starting it again per test costs seconds.
282
+ *
283
+ * The Astur fixture calls this after every test, so tabs cannot accumulate
284
+ * and no test inherits the previous one's page.
285
+ */
286
+ close: async () => {
287
+ await this.closeBrowserPage();
288
+ const id = this.browserTabId;
289
+ this.browserTabId = undefined;
290
+ if (id && this.session.closeBrowserTab) {
291
+ await this.session.closeBrowserTab(id).catch(() => undefined);
292
+ }
293
+ }
294
+ };
157
295
  keyboard = {
158
296
  isVisible: async () => {
159
297
  if (!this.session.getKeyboardState) {
@@ -284,6 +422,9 @@ export class AsturDevice {
284
422
  getByType(value, options) {
285
423
  return this.find(by.type(value, options));
286
424
  }
425
+ getByPlaceholder(value, options) {
426
+ return this.find(by.placeholder(value, options));
427
+ }
287
428
  inspector(options) {
288
429
  return createInspectorSession(this.session, options);
289
430
  }
@@ -311,6 +452,9 @@ export class AsturDevice {
311
452
  async pressAndHold(point, options) {
312
453
  await this.longPress(point, options);
313
454
  }
455
+ async getOrientation() {
456
+ return this.orientation.get();
457
+ }
314
458
  async setOrientation(orientation) {
315
459
  if (!this.session.setOrientation) {
316
460
  throw new AsturError('ORIENTATION_NOT_SUPPORTED', `${this.deviceInfo.platform} does not expose orientation control yet.`);
@@ -409,7 +553,83 @@ export class AsturDevice {
409
553
  }
410
554
  return new WebContext(await this.session.createWebEvaluator(selector));
411
555
  }
556
+ /**
557
+ * Re-resolves the page after a history navigation.
558
+ *
559
+ * No URL to match on here — where `back()` lands is exactly what the test is
560
+ * asking about — so this takes whichever page the browser now shows.
561
+ */
562
+ /**
563
+ * Runs a history navigation on the attached tab and waits for it to settle.
564
+ *
565
+ * Deliberately stays on the same target rather than re-resolving. A browser
566
+ * keeps every tab a suite has opened, several on the same URL, so "find the
567
+ * page again" is ambiguous in a way it never is for an app's single WebView —
568
+ * and picking wrong silently drives a frozen background tab. Chromium keeps
569
+ * one target across a same-tab navigation; if the transport does die, the
570
+ * re-resolve below is the fallback rather than the norm.
571
+ */
572
+ async renavigate(expression, timeout, expectUrl) {
573
+ const page = this.requireBrowserPage();
574
+ const token = await markNavigation(page);
575
+ await runNavigation(page, expression);
576
+ if (await settlePage(page, timeout ?? DEFAULT_PAGE_TIMEOUT_MS, { token, expectUrl })) {
577
+ return page;
578
+ }
579
+ await this.closeBrowserPage();
580
+ return this.resolveBrowserPage(expectUrl, timeout);
581
+ }
582
+ /**
583
+ * Brings the attached tab to `url`, navigating only if it is not already
584
+ * there — so an intent that happened to land correctly costs nothing.
585
+ */
586
+ async ensureAt(page, url, timeout) {
587
+ const timeoutMs = timeout ?? DEFAULT_PAGE_TIMEOUT_MS;
588
+ const alreadyThere = pageMatcher(url).test(await currentUrl(page) ?? '');
589
+ const token = await markNavigation(page);
590
+ // Load even when the tab already shows this URL. Reusing a tab is what keeps
591
+ // the browser from leaking one per test, but a reused tab still carries the
592
+ // previous test's DOM — a filled field, a submitted form — and skipping the
593
+ // load would silently hand that state to the next test.
594
+ await runNavigation(page, alreadyThere ? 'location.reload()' : `location.href = ${JSON.stringify(url)}`);
595
+ if (await settlePage(page, timeoutMs, { token, expectUrl: url })) {
596
+ return page;
597
+ }
598
+ await this.closeBrowserPage();
599
+ return this.resolveBrowserPage(url, timeout);
600
+ }
601
+ /** Attaches to an already-open page, or resolves undefined. Never throws. */
602
+ async tryResolveBrowserPage(timeoutMs) {
603
+ if (!this.session.createWebEvaluator) {
604
+ return undefined;
605
+ }
606
+ return this.resolveBrowserPage(undefined, timeoutMs).catch(() => undefined);
607
+ }
608
+ async resolveBrowserPage(url, timeout) {
609
+ if (!this.session.createWebEvaluator) {
610
+ throw new AsturError('BROWSER_NOT_SUPPORTED', `${this.deviceInfo.platform} has no DOM transport, so a browser page cannot be driven.`);
611
+ }
612
+ const timeoutMs = timeout ?? DEFAULT_PAGE_TIMEOUT_MS;
613
+ const page = await connectBrowserPage((selector) => this.session.createWebEvaluator(selector), { url, timeoutMs });
614
+ // Settle before handing the page over, so the first assertion is not racing
615
+ // a document that is still parsing.
616
+ await waitForLoad(page, timeoutMs);
617
+ this.browserPage = page;
618
+ return page;
619
+ }
620
+ requireBrowserPage() {
621
+ if (!this.browserPage) {
622
+ throw new AsturError('BROWSER_PAGE_NOT_OPEN', 'No browser page is open. Call device.browser.open(url) first.');
623
+ }
624
+ return this.browserPage;
625
+ }
626
+ async closeBrowserPage() {
627
+ const page = this.browserPage;
628
+ this.browserPage = undefined;
629
+ await page?.close().catch(() => undefined);
630
+ }
412
631
  async close() {
632
+ await this.browser.close().catch(() => undefined);
413
633
  await this.session.close();
414
634
  }
415
635
  }
@@ -437,6 +657,47 @@ function appIdentifier(capabilities, target) {
437
657
  }
438
658
  return identifier;
439
659
  }
660
+ async function installAppUnderTest(session, platform) {
661
+ const app = session.capabilities.app;
662
+ if (!app?.path || app.install === 'never') {
663
+ return;
664
+ }
665
+ const identifier = app.packageName ?? app.bundleId;
666
+ // Kept as it always behaved while it is phased out: a clean install, which
667
+ // also wipes app data. `install: 'always'` installs over the top instead.
668
+ if (platform === 'android' && process.env.ASTUR_ANDROID_APP_FORCE_INSTALL === '1') {
669
+ if (identifier) {
670
+ try {
671
+ await session.uninstallApp(identifier);
672
+ }
673
+ catch {
674
+ // The package may not be installed yet; the install below is still
675
+ // the authoritative operation.
676
+ }
677
+ }
678
+ await session.installApp(app.path);
679
+ return;
680
+ }
681
+ if (app.install !== 'always' && identifier && await hasInstalledBuild(session, identifier, app.path)) {
682
+ return;
683
+ }
684
+ await session.installApp(app.path);
685
+ }
686
+ /**
687
+ * Whether the device already has the requested build. A driver that can compare
688
+ * builds decides, and "cannot tell" counts as no: a suite quietly running
689
+ * against a stale build costs more than a slower start. Drivers that cannot
690
+ * compare yet fall back to asking whether the package is present at all.
691
+ */
692
+ async function hasInstalledBuild(session, identifier, path) {
693
+ if (session.isInstalledAppCurrent) {
694
+ return (await session.isInstalledAppCurrent(identifier, path).catch(() => undefined)) === true;
695
+ }
696
+ if (session.isAppInstalled) {
697
+ return session.isAppInstalled(identifier).catch(() => false);
698
+ }
699
+ return false;
700
+ }
440
701
  export class AsturRuntime {
441
702
  drivers = new Map();
442
703
  register(driver) {
@@ -452,36 +713,31 @@ export class AsturRuntime {
452
713
  const devices = await Promise.all(drivers.map((driver) => driver.listDevices()));
453
714
  return devices.flat();
454
715
  }
716
+ /**
717
+ * The device `createDevice(config)` would open, found without touching it.
718
+ * Reservation locks this, so two spellings of one device collide.
719
+ */
720
+ async findDevice(config) {
721
+ const capabilities = normalizeCapabilities(config);
722
+ return this.requireDriver(capabilities.platform).findDevice?.(capabilities.device);
723
+ }
455
724
  async createDevice(config) {
456
725
  const capabilities = await materializeCapabilities(normalizeCapabilities(config));
457
726
  const driver = this.requireDriver(capabilities.platform);
458
727
  const session = await driver.createSession(capabilities);
459
- const app = session.capabilities.app;
460
- if (app?.path) {
461
- const identifier = app.packageName ?? app.bundleId;
462
- const forceInstall = capabilities.platform === 'android'
463
- && process.env.ASTUR_ANDROID_APP_FORCE_INSTALL === '1';
464
- if (forceInstall) {
465
- if (identifier) {
466
- try {
467
- await session.uninstallApp(identifier);
468
- }
469
- catch {
470
- // The package may not be installed yet; the install below is still
471
- // the authoritative operation.
472
- }
473
- }
474
- await session.installApp(app.path);
475
- }
476
- else if (identifier && session.isAppInstalled) {
477
- const installed = await session.isAppInstalled(identifier).catch(() => false);
478
- if (!installed) {
479
- await session.installApp(app.path);
480
- }
728
+ try {
729
+ await installAppUnderTest(session, capabilities.platform);
730
+ }
731
+ catch (error) {
732
+ // The session already holds an agent process, port forwards, and a
733
+ // device; a failed install must not strand them.
734
+ try {
735
+ await session.close();
481
736
  }
482
- else {
483
- await session.installApp(app.path);
737
+ catch {
738
+ // The install failure is the error worth reporting.
484
739
  }
740
+ throw error;
485
741
  }
486
742
  return new AsturDevice(session);
487
743
  }