@vostride/agent-qa-ios 0.1.21 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { PlatformAdapter, PlatformConfig, ObserveOptions, ScreenState, Action, ActionResult, ConsoleLogEntry } from '@vostride/agent-qa-core';
1
+ import { PlatformAdapter, PlatformConfig, LiveStreamCapability, ObserveOptions, ActionsFor, ActionResult, ConsoleLogEntry } from '@vostride/agent-qa-runner';
2
+ import { ScreenState } from '@vostride/agent-qa-schema';
2
3
 
3
- declare class IOSPlatformAdapter implements PlatformAdapter {
4
+ declare class IOSPlatformAdapter implements PlatformAdapter<'ios'> {
4
5
  readonly platform: "ios";
5
6
  private driver;
6
7
  private lastRefs;
@@ -8,14 +9,28 @@ declare class IOSPlatformAdapter implements PlatformAdapter {
8
9
  private activeWebContext;
9
10
  private webContextChecked;
10
11
  private currentContext;
12
+ private liveStreamCapability;
11
13
  private consoleLogs;
12
14
  private consoleDrainIndex;
13
15
  private captureConsole;
14
16
  private bundleId;
17
+ private appRegistry;
18
+ private sessionSnapshotDepth;
19
+ private snapshotDepth;
20
+ private readsAtLoweredDepth;
21
+ private snapshotDepthWarned;
15
22
  setup(config: PlatformConfig): Promise<void>;
16
23
  cleanup(): Promise<void>;
24
+ /**
25
+ * 428 D-11: the labelled 1s snapshot preview, over `captureScreenshot()` — `takeScreenshot()`
26
+ * and nothing else. Never `screenshot()`: that one switches the Appium context, and a tick
27
+ * landing between a step's context switch and its command would run the command in the wrong
28
+ * context. Declared before the driver exists (a capture then answers `undefined`), so the
29
+ * composition's selection never falls through to `screenshot()`.
30
+ */
31
+ get liveStream(): LiveStreamCapability;
17
32
  observe(_options?: ObserveOptions): Promise<ScreenState>;
18
- execute(action: Action): Promise<ActionResult>;
33
+ execute(action: ActionsFor<'ios'>): Promise<ActionResult>;
19
34
  screenshot(): Promise<Buffer | undefined>;
20
35
  pollDeviceLogs(): Promise<void>;
21
36
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
@@ -23,8 +38,91 @@ declare class IOSPlatformAdapter implements PlatformAdapter {
23
38
  private getWebContext;
24
39
  /** Invalidate the cached web context so next getWebContext() re-queries. */
25
40
  private invalidateWebContext;
41
+ private readForegroundBundleId;
42
+ private isBrowserSession;
26
43
  private ensureContext;
27
44
  private captureScreenshot;
45
+ private readIOSPageSource;
46
+ private countLoweredRead;
47
+ private tapAt;
48
+ private readRect;
49
+ /**
50
+ * The ref's own text-entry element: candidates of its XCUI type (selector built from the fixed
51
+ * type list only, never from app-supplied text) whose rect matches the observed bounds. Only a
52
+ * unique match is used; two or more matches, or none, ⇒ undefined. Position never selects.
53
+ */
54
+ private locateIOSTextTarget;
55
+ private readIOSFocusedIds;
56
+ /**
57
+ * WDA's typing taps an element that lacks keyboard focus and then sends keystrokes without
58
+ * re-checking focus, so they land wherever focus is. Text is typed only once the target (or
59
+ * a descendant) holds keyboard focus.
60
+ */
61
+ private confirmIOSKeyboardFocus;
62
+ private textInputRefusal;
63
+ /** Gate → own-element lookup → tap → keyboard-focus check shared by fill and clearText. */
64
+ private focusIOSTextTarget;
65
+ /** A non-empty empty-field hint (XCUITest placeholderValue); undefined when absent. */
66
+ private readIOSPlaceholder;
67
+ /** Read a focused element's `value` attribute; undefined when nothing is readable. */
68
+ private readIOSValue;
69
+ /**
70
+ * EXEC-01 iOS fill compound (D-05..D-08). From the SAME focused-element handle: (append) capture
71
+ * the prior value FIRST via getAttribute('value') then addValue, or (replace) setValue; RE-READ
72
+ * via getAttribute('value') on that same handle; verdict via compareFillReread. Secure fields
73
+ * (nativeType XCUIElementTypeSecureTextField) take the non-empty-only lane — the comparator yields
74
+ * length sentinels so no raw value enters the result (T-359-02); bullet masking is tolerated
75
+ * (A3/Pitfall 7 — never a length compare). On a passing re-read AND submit, a return/newline is
76
+ * delivered AFTER the re-read (D-07). Single typing attempt; a mismatch is success:false + §7.1.
77
+ *
78
+ * Append (437 FA-1, owner 2026-10-08): the XCUITest `value` attribute often lags after addValue,
79
+ * so a re-read equal to the prior cannot show the appended text. That fill is recorded unverified:
80
+ * never exact, and never a mismatch. Every fill records the shared verdict as `fillVerdict`.
81
+ * An empty field reads as its placeholder, so an append prior equal to it counts as empty.
82
+ *
83
+ * Return in a multi-line field adds a new line instead of submitting, so a multi-line submit is
84
+ * never sent and is recorded as such.
85
+ *
86
+ * An unreadable re-read is unverified and does not stop a requested Return, as on Android (D-09,
87
+ * D-10; owner 2026-10-09), but focus is confirmed once first and a Return is held as focus-lost
88
+ * when the field no longer has it (444.1 D-10).
89
+ */
90
+ private fillIOSCompound;
91
+ /**
92
+ * EXEC-02 platform primitives injected into the shared runner scroll loops (D-02/D-03). The swipe
93
+ * is a page-sized directional gesture (inverted to the finger direction) that reports unknown
94
+ * movement; nativeSearchScroll drives
95
+ * the XCUITest `mobile: scroll` predicateString rung over an injection-escaped target; readInterimTree
96
+ * is a light page-source parse — NO refMap mint, NO screenshot, lastRefs untouched.
97
+ */
98
+ private buildIOSScrollPrimitives;
99
+ /**
100
+ * EXEC-03 openApp (D-10/D-12, Pitfall 5). Resolve a human name to a bundle id (or validate an
101
+ * explicit bundleId) over the session-cached registry, then launch via activateApp. On real devices
102
+ * `mobile: listApps` enumerates the registry; on simulators it throws, leaving the registry
103
+ * unavailable — the appName lane then mints a structured §7.1 error directing to an explicit
104
+ * bundleId, and the bundleId lane validates without the registry (isAppInstalled / activateApp
105
+ * error conversion, A2). Never a best-guess launch (T-359-04); an invalid bundle never succeeds.
106
+ */
107
+ private openApp;
108
+ /**
109
+ * Explicit `{bundleId}` launch (D-12, A2). With a registry, validate membership; without one
110
+ * (simulator) validate via `driver.isAppInstalled` when the driver exposes it, otherwise attempt
111
+ * `activateApp` and convert a driver rejection into the structured §7.1 error. An invalid bundle
112
+ * NEVER returns success:true.
113
+ */
114
+ private openByBundleId;
115
+ /** Return the cached registry, enumerating once on first use. Failed enumeration returns null (uncached). */
116
+ private ensureAppRegistry;
117
+ /**
118
+ * Enumerate installed apps through the driver only (ownership contract — webdriverio only, no
119
+ * child_process/simctl). `mobile: listApps` maps bundle ids → AppRegistryEntry with CFBundleName
120
+ * labels when present (D-10 — no per-app round-trips). It throws on simulators (Pitfall 5) ⇒ null,
121
+ * leaving enumeration unavailable WITHOUT crashing.
122
+ */
123
+ private enumerateApps;
124
+ /** Coerce a `mobile: listApps` result (bundle-id-keyed map, or an array of entries) into the registry. */
125
+ private mapListApps;
28
126
  private executeAction;
29
127
  }
30
128