execbro 2.8.3 → 2.8.5

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.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/build/__tests__/unit/metroGateReconnect.test.d.ts +2 -0
  3. package/build/__tests__/unit/metroGateReconnect.test.d.ts.map +1 -0
  4. package/build/__tests__/unit/metroGateReconnect.test.js +98 -0
  5. package/build/__tests__/unit/metroGateReconnect.test.js.map +1 -0
  6. package/build/__tests__/unit/pressablesLongPress.test.d.ts +2 -0
  7. package/build/__tests__/unit/pressablesLongPress.test.d.ts.map +1 -0
  8. package/build/__tests__/unit/pressablesLongPress.test.js +91 -0
  9. package/build/__tests__/unit/pressablesLongPress.test.js.map +1 -0
  10. package/build/__tests__/unit/socketLifecycle.test.d.ts +2 -0
  11. package/build/__tests__/unit/socketLifecycle.test.d.ts.map +1 -0
  12. package/build/__tests__/unit/socketLifecycle.test.js +66 -0
  13. package/build/__tests__/unit/socketLifecycle.test.js.map +1 -0
  14. package/build/__tests__/unit/swipeProbeWithoutRn.test.d.ts +2 -0
  15. package/build/__tests__/unit/swipeProbeWithoutRn.test.d.ts.map +1 -0
  16. package/build/__tests__/unit/swipeProbeWithoutRn.test.js +44 -0
  17. package/build/__tests__/unit/swipeProbeWithoutRn.test.js.map +1 -0
  18. package/build/__tests__/unit/tapAndroidSerial.test.d.ts +2 -0
  19. package/build/__tests__/unit/tapAndroidSerial.test.d.ts.map +1 -0
  20. package/build/__tests__/unit/tapAndroidSerial.test.js +179 -0
  21. package/build/__tests__/unit/tapAndroidSerial.test.js.map +1 -0
  22. package/build/__tests__/unit/tapDuration.test.d.ts +2 -0
  23. package/build/__tests__/unit/tapDuration.test.d.ts.map +1 -0
  24. package/build/__tests__/unit/tapDuration.test.js +168 -0
  25. package/build/__tests__/unit/tapDuration.test.js.map +1 -0
  26. package/build/__tests__/unit/tapLongPressReport.test.d.ts +2 -0
  27. package/build/__tests__/unit/tapLongPressReport.test.d.ts.map +1 -0
  28. package/build/__tests__/unit/tapLongPressReport.test.js +167 -0
  29. package/build/__tests__/unit/tapLongPressReport.test.js.map +1 -0
  30. package/build/core/android.d.ts +1 -1
  31. package/build/core/android.d.ts.map +1 -1
  32. package/build/core/android.js +4 -1
  33. package/build/core/android.js.map +1 -1
  34. package/build/core/connection.d.ts.map +1 -1
  35. package/build/core/connection.js +14 -5
  36. package/build/core/connection.js.map +1 -1
  37. package/build/core/connectionState.d.ts +7 -0
  38. package/build/core/connectionState.d.ts.map +1 -1
  39. package/build/core/connectionState.js +11 -0
  40. package/build/core/connectionState.js.map +1 -1
  41. package/build/core/guides.d.ts.map +1 -1
  42. package/build/core/guides.js +12 -0
  43. package/build/core/guides.js.map +1 -1
  44. package/build/core/index.d.ts +1 -1
  45. package/build/core/index.d.ts.map +1 -1
  46. package/build/core/index.js +1 -1
  47. package/build/core/index.js.map +1 -1
  48. package/build/core/nativeOnlyHints.d.ts +7 -1
  49. package/build/core/nativeOnlyHints.d.ts.map +1 -1
  50. package/build/core/nativeOnlyHints.js +32 -4
  51. package/build/core/nativeOnlyHints.js.map +1 -1
  52. package/build/core/pressables.d.ts +1 -0
  53. package/build/core/pressables.d.ts.map +1 -1
  54. package/build/core/pressables.js +32 -8
  55. package/build/core/pressables.js.map +1 -1
  56. package/build/core/state.d.ts +1 -0
  57. package/build/core/state.d.ts.map +1 -1
  58. package/build/core/state.js +4 -0
  59. package/build/core/state.js.map +1 -1
  60. package/build/core/swipeDiagnosis.d.ts +1 -0
  61. package/build/core/swipeDiagnosis.d.ts.map +1 -1
  62. package/build/core/swipeDiagnosis.js +18 -5
  63. package/build/core/swipeDiagnosis.js.map +1 -1
  64. package/build/pro/tap.d.ts +12 -0
  65. package/build/pro/tap.d.ts.map +1 -1
  66. package/build/pro/tap.js +102 -34
  67. package/build/pro/tap.js.map +1 -1
  68. package/build/pro/verifyAction.d.ts +3 -1
  69. package/build/pro/verifyAction.d.ts.map +1 -1
  70. package/build/pro/verifyAction.js +7 -7
  71. package/build/pro/verifyAction.js.map +1 -1
  72. package/build/tools/componentTools.js +4 -4
  73. package/build/tools/componentTools.js.map +1 -1
  74. package/build/tools/interactionTools.d.ts.map +1 -1
  75. package/build/tools/interactionTools.js +20 -5
  76. package/build/tools/interactionTools.js.map +1 -1
  77. package/package.json +1 -1
  78. package/tools.json +1 -0
package/README.md CHANGED
@@ -46,7 +46,7 @@ Linking your installation here is also **required to unlock [ExecBro Pro](#prici
46
46
  - **Unified Tap** - Single `tap` tool with automatic fallback chain: fiber tree → accessibility → OCR → coordinates. Auto-detects platform, accepts coordinates from screenshots and layout tools unchanged. Returns post-tap screenshot and verifies visual change by default
47
47
  - **Unified Swipe** - Single `swipe` tool that auto-routes to iOS or Android based on the connected device. Takes coordinates in the same screen space as the layout tools and screenshots — no conversion — and returns a `verification.meaningful` signal so agents detect end-of-list, non-scrollable surfaces, and missed coordinates. Essential for scrolling virtualized lists (FlatList/SectionList) where off-screen items aren't in the fiber tree
48
48
  - **Real Multi-Touch Pinch** *(Android emulator only — iOS in progress)* - A `pinch` tool that sends two genuine kernel touch contacts through the Android emulator's multi-touch bridge, so it zooms maps, galleries, WebViews, and native views alike — it works below the app, not through React Native. Returns the same `verification.meaningful` signal as `swipe`, and refuses on unsupported targets instead of faking a result
49
- - **UI Automation** - Swipe, long press, key events, and text input on both platforms. On Bridgeless/Fabric apps, `dismiss_keyboard` operates on whatever has focus, and `ios_input_text` / `android_input_text` accept `replace:true` to overwrite pre-filled values — updating React state through `onChangeText` so controlled components (Formik, react-hook-form, useState) stay consistent
49
+ - **UI Automation** - Swipe, long press (`tap` with `duration`, resolving the target by testID/text/component), key events, and text input on both platforms. On Bridgeless/Fabric apps, `dismiss_keyboard` operates on whatever has focus, and `ios_input_text` / `android_input_text` accept `replace:true` to overwrite pre-filled values — updating React state through `onChangeText` so controlled components (Formik, react-hook-form, useState) stay consistent
50
50
  - **Accessibility Inspection** - Query UI hierarchy to find elements by text, label, or resource ID
51
51
  - **OCR Text Extraction** - Extract visible text with tap-ready coordinates via Google Cloud Vision (works on any screen content)
52
52
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=metroGateReconnect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metroGateReconnect.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/metroGateReconnect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect, beforeEach } from "@jest/globals";
2
+ import WebSocket from "ws";
3
+ const { connectedApps } = await import("../../core/state.js");
4
+ const { awaitMetro, buildMetroMissingHint } = await import("../../core/nativeOnlyHints.js");
5
+ const { saveReconnectionTimer, cancelReconnectionTimer } = await import("../../core/connectionState.js");
6
+ function connectApp(key = "app-1") {
7
+ connectedApps.set(key, {
8
+ ws: { readyState: WebSocket.OPEN },
9
+ deviceInfo: {
10
+ id: key,
11
+ title: "Hermes React Native",
12
+ description: "",
13
+ appId: "com.test",
14
+ type: "node",
15
+ webSocketDebuggerUrl: "ws://localhost:8081/x",
16
+ deviceName: "iPhone Air"
17
+ },
18
+ port: 8081,
19
+ platform: "ios"
20
+ });
21
+ }
22
+ function fakeSleep() {
23
+ const waits = [];
24
+ return {
25
+ waits,
26
+ sleep: async (ms) => {
27
+ waits.push(ms);
28
+ }
29
+ };
30
+ }
31
+ describe("awaitMetro", () => {
32
+ beforeEach(() => {
33
+ connectedApps.clear();
34
+ cancelReconnectionTimer("app-1");
35
+ });
36
+ it("answers immediately when an app is connected", async () => {
37
+ connectApp();
38
+ const { waits, sleep } = fakeSleep();
39
+ expect(await awaitMetro({ sleep })).toBe(true);
40
+ expect(waits).toEqual([]);
41
+ });
42
+ it("does not wait when nothing is reconnecting", async () => {
43
+ const { waits, sleep } = fakeSleep();
44
+ expect(await awaitMetro({ sleep })).toBe(false);
45
+ expect(waits).toEqual([]);
46
+ });
47
+ it("waits for an in-flight reconnection and reports the recovery", async () => {
48
+ const timer = setTimeout(() => { }, 60_000);
49
+ saveReconnectionTimer("app-1", timer);
50
+ const { waits, sleep } = fakeSleep();
51
+ let polls = 0;
52
+ const countingSleep = async (ms) => {
53
+ await sleep(ms);
54
+ if (++polls === 3)
55
+ connectApp();
56
+ };
57
+ expect(await awaitMetro({ sleep: countingSleep })).toBe(true);
58
+ expect(waits.length).toBe(3);
59
+ clearTimeout(timer);
60
+ });
61
+ it("gives up inside its budget when the reconnection never lands", async () => {
62
+ const timer = setTimeout(() => { }, 60_000);
63
+ saveReconnectionTimer("app-1", timer);
64
+ const { waits, sleep } = fakeSleep();
65
+ expect(await awaitMetro({ timeoutMs: 2000, sleep })).toBe(false);
66
+ expect(waits.reduce((a, b) => a + b, 0)).toBeLessThanOrEqual(2000);
67
+ expect(waits.length).toBeGreaterThan(0);
68
+ clearTimeout(timer);
69
+ });
70
+ });
71
+ describe("the no-Metro hint", () => {
72
+ it("names the reconnecting device instead of telling the user to scan again", () => {
73
+ const hint = buildMetroMissingHint({
74
+ toolName: "get_screen_state",
75
+ devices: { ios: true, android: true, any: true },
76
+ reconnecting: ["iPhone Air"]
77
+ });
78
+ expect(hint).toMatch(/iPhone Air/);
79
+ expect(hint).toMatch(/reconnect/i);
80
+ expect(hint).not.toMatch(/run scan_metro/i);
81
+ });
82
+ it("does not present an attached device as if it were the connection", () => {
83
+ const hint = buildMetroMissingHint({
84
+ toolName: "get_screen_state",
85
+ devices: { ios: true, android: true, any: true }
86
+ });
87
+ expect(hint).toMatch(/attached/i);
88
+ expect(hint).toMatch(/scan_metro/);
89
+ });
90
+ it("still guides the user when nothing is running at all", () => {
91
+ const hint = buildMetroMissingHint({
92
+ toolName: "get_screen_state",
93
+ devices: { ios: false, android: false, any: false }
94
+ });
95
+ expect(hint).toMatch(/No running simulators or devices/i);
96
+ });
97
+ });
98
+ //# sourceMappingURL=metroGateReconnect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metroGateReconnect.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/metroGateReconnect.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pressablesLongPress.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pressablesLongPress.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/pressablesLongPress.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect, jest, beforeEach } from "@jest/globals";
2
+ const evaluated = [];
3
+ let evalResult = null;
4
+ jest.unstable_mockModule("../../core/jsExecute.js", () => ({
5
+ executeInApp: async (expression) => {
6
+ evaluated.push(expression);
7
+ return { success: true, result: JSON.stringify(evalResult) };
8
+ },
9
+ delay: async () => { }
10
+ }));
11
+ const { pressElement } = await import("../../core/pressables.js");
12
+ function fiber(props, type = "View", children = []) {
13
+ const node = {
14
+ type,
15
+ memoizedProps: props,
16
+ stateNode: { measureInWindow: (cb) => cb(10, 20, 100, 50) },
17
+ child: null,
18
+ sibling: null,
19
+ return: null
20
+ };
21
+ let prev = null;
22
+ for (const c of children) {
23
+ c.return = node;
24
+ if (prev)
25
+ prev.sibling = c;
26
+ else
27
+ node.child = c;
28
+ prev = c;
29
+ }
30
+ return node;
31
+ }
32
+ async function search(options, root) {
33
+ evaluated.length = 0;
34
+ evalResult = { dispatched: 1 };
35
+ await pressElement(options);
36
+ const globalThisStub = {
37
+ __REACT_DEVTOOLS_GLOBAL_HOOK__: {
38
+ getFiberRoots: () => new Set([{ current: root }]),
39
+ renderers: new Map()
40
+ }
41
+ };
42
+ let last = null;
43
+ for (const expression of evaluated) {
44
+ const fn = new Function("globalThis", `return (${expression.trim()});`);
45
+ last = fn(globalThisStub);
46
+ }
47
+ return typeof last === "string" ? JSON.parse(last) : last;
48
+ }
49
+ describe("fiber search and onLongPress", () => {
50
+ beforeEach(() => {
51
+ evaluated.length = 0;
52
+ });
53
+ it("ignores a long-press-only element for an ordinary tap", async () => {
54
+ const root = fiber({}, "View", [
55
+ fiber({ testID: "row-3", onLongPress: () => { } }, "View", [
56
+ fiber({ children: "Row 3" }, "Text")
57
+ ])
58
+ ]);
59
+ const out = await search({ testID: "row-3" }, root);
60
+ expect(out.needsNativeTap).toBeUndefined();
61
+ expect(out.error).toBeDefined();
62
+ });
63
+ it("finds a long-press-only element when a hold was requested", async () => {
64
+ const root = fiber({}, "View", [
65
+ fiber({ testID: "row-3", onLongPress: () => { } }, "View", [
66
+ fiber({ children: "Row 3" }, "Text")
67
+ ])
68
+ ]);
69
+ const out = await search({ testID: "row-3", longPress: true }, root);
70
+ expect(out.needsNativeTap).toBe(true);
71
+ expect(out.hasLongPress).toBe(true);
72
+ });
73
+ it("reports an ordinary button as having no long-press handler", async () => {
74
+ const root = fiber({}, "View", [
75
+ fiber({ testID: "save", onPress: () => { } }, "View", [
76
+ fiber({ children: "Save" }, "Text")
77
+ ])
78
+ ]);
79
+ const out = await search({ testID: "save", longPress: true }, root);
80
+ expect(out.needsNativeTap).toBe(true);
81
+ expect(out.hasLongPress).toBe(false);
82
+ });
83
+ it("still finds ordinary pressables when a hold was requested", async () => {
84
+ const root = fiber({}, "View", [
85
+ fiber({ onPress: () => { } }, "View", [fiber({ children: "Save" }, "Text")])
86
+ ]);
87
+ const out = await search({ text: "Save", longPress: true }, root);
88
+ expect(out.needsNativeTap).toBe(true);
89
+ });
90
+ });
91
+ //# sourceMappingURL=pressablesLongPress.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pressablesLongPress.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/pressablesLongPress.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=socketLifecycle.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socketLifecycle.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/socketLifecycle.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect, beforeEach } from "@jest/globals";
2
+ import WebSocket from "ws";
3
+ const { connectedApps, isSupersededSocket } = await import("../../core/state.js");
4
+ const { shouldTerminateForMissedPong } = await import("../../core/connectionState.js");
5
+ function app(ws) {
6
+ return {
7
+ ws: ws,
8
+ deviceInfo: {
9
+ id: "dev-1",
10
+ title: "Hermes React Native",
11
+ description: "",
12
+ appId: "com.test",
13
+ type: "node",
14
+ webSocketDebuggerUrl: "ws://localhost:8081/x",
15
+ deviceName: "iPhone Air"
16
+ },
17
+ port: 8081,
18
+ platform: "ios"
19
+ };
20
+ }
21
+ describe("isSupersededSocket", () => {
22
+ beforeEach(() => connectedApps.clear());
23
+ it("says a socket still holding its entry is not superseded", () => {
24
+ const live = { readyState: WebSocket.OPEN };
25
+ connectedApps.set("k", app(live));
26
+ expect(isSupersededSocket("k", live)).toBe(false);
27
+ });
28
+ it("says a replaced socket is superseded", () => {
29
+ const old = { readyState: WebSocket.CLOSED };
30
+ const live = { readyState: WebSocket.OPEN };
31
+ connectedApps.set("k", app(old));
32
+ connectedApps.set("k", app(live));
33
+ expect(isSupersededSocket("k", old)).toBe(true);
34
+ expect(isSupersededSocket("k", live)).toBe(false);
35
+ });
36
+ it("does not call an unregistered socket superseded", () => {
37
+ expect(isSupersededSocket("k", { readyState: WebSocket.OPEN })).toBe(false);
38
+ });
39
+ });
40
+ describe("shouldTerminateForMissedPong", () => {
41
+ const now = 1_000_000;
42
+ const quietWindowMs = 10_000;
43
+ it("keeps a socket whose pong arrived", () => {
44
+ expect(shouldTerminateForMissedPong({ pongReceived: true, lastCdpMessageAt: null, now, quietWindowMs })).toBe(false);
45
+ });
46
+ it("keeps a socket that is still carrying CDP traffic", () => {
47
+ expect(shouldTerminateForMissedPong({
48
+ pongReceived: false,
49
+ lastCdpMessageAt: new Date(now - 2_000),
50
+ now,
51
+ quietWindowMs
52
+ })).toBe(false);
53
+ });
54
+ it("terminates when the pong is missed and the socket has gone quiet", () => {
55
+ expect(shouldTerminateForMissedPong({
56
+ pongReceived: false,
57
+ lastCdpMessageAt: new Date(now - 30_000),
58
+ now,
59
+ quietWindowMs
60
+ })).toBe(true);
61
+ });
62
+ it("terminates when there was never any traffic to vouch for it", () => {
63
+ expect(shouldTerminateForMissedPong({ pongReceived: false, lastCdpMessageAt: null, now, quietWindowMs })).toBe(true);
64
+ });
65
+ });
66
+ //# sourceMappingURL=socketLifecycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socketLifecycle.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/socketLifecycle.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=swipeProbeWithoutRn.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipeProbeWithoutRn.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/swipeProbeWithoutRn.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect, jest } from "@jest/globals";
2
+ const execCalls = [];
3
+ let execBehaviour = async () => ({ success: false });
4
+ jest.unstable_mockModule("../../core/jsExecute.js", () => ({
5
+ executeInApp: async (...args) => {
6
+ execCalls.push(args);
7
+ return execBehaviour();
8
+ },
9
+ delay: async () => { }
10
+ }));
11
+ const { probeScrollAt, explainNoOpSwipe } = await import("../../core/swipeDiagnosis.js");
12
+ describe("probeScrollAt without a React Native connection", () => {
13
+ it("reports the probe as unavailable instead of throwing", async () => {
14
+ execCalls.length = 0;
15
+ execBehaviour = () => {
16
+ throw new Error('No connected device matches "emulator-5556"');
17
+ };
18
+ const probe = await probeScrollAt(446, 1330, "emulator-5556");
19
+ expect(probe.found).toBe(false);
20
+ expect(probe.unavailable).toBe(true);
21
+ });
22
+ it("does not claim the gesture missed a scroll view when it could not look", async () => {
23
+ const unavailable = explainNoOpSwipe({ found: false, unavailable: true }, { x: 446, y: 1330 });
24
+ expect(unavailable).toMatch(/no React Native connection|could not/i);
25
+ expect(unavailable).not.toMatch(/did not land on a scrollable surface/);
26
+ const genuinelyMissed = explainNoOpSwipe({ found: false }, { x: 446, y: 1330 });
27
+ expect(genuinelyMissed).toMatch(/did not land on a scrollable surface/);
28
+ });
29
+ it("treats a failed probe the same as a thrown one — both mean we could not look", async () => {
30
+ execCalls.length = 0;
31
+ execBehaviour = async () => ({ success: false, error: "Not connected to any app" });
32
+ const probe = await probeScrollAt(446, 1330, "emulator-5556");
33
+ expect(probe.found).toBe(false);
34
+ expect(probe.unavailable).toBe(true);
35
+ });
36
+ it("still reports a real miss when the app answers", async () => {
37
+ execCalls.length = 0;
38
+ execBehaviour = async () => ({ success: true, result: JSON.stringify({ found: false }) });
39
+ const probe = await probeScrollAt(446, 1330, "emulator-5556");
40
+ expect(probe.found).toBe(false);
41
+ expect(probe.unavailable).toBeUndefined();
42
+ });
43
+ });
44
+ //# sourceMappingURL=swipeProbeWithoutRn.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipeProbeWithoutRn.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/swipeProbeWithoutRn.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tapAndroidSerial.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapAndroidSerial.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/tapAndroidSerial.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,179 @@
1
+ import { describe, it, expect, jest, beforeEach } from "@jest/globals";
2
+ import WebSocket from "ws";
3
+ const TARGET = "emulator-5556";
4
+ const DEFAULT = "emulator-5554";
5
+ const adbCalls = [];
6
+ const verifyCalls = [];
7
+ jest.unstable_mockModule("../../core/exec.js", () => ({
8
+ execFileAsync: async (file, args) => {
9
+ if (file === "adb")
10
+ adbCalls.push(args);
11
+ if (args?.[0] === "devices") {
12
+ return { stdout: `List of devices attached\n${DEFAULT}\tdevice\n${TARGET}\tdevice\n`, stderr: "" };
13
+ }
14
+ if (args?.includes("wm density"))
15
+ return { stdout: "Physical density: 160", stderr: "" };
16
+ return { stdout: "", stderr: "" };
17
+ },
18
+ execAsync: async () => ({ stdout: "", stderr: "" }),
19
+ quoteForDeviceShell: (v) => v,
20
+ withCancelableTimeout: async (p) => p
21
+ }));
22
+ jest.unstable_mockModule("../../core/deviceResolver.js", () => ({
23
+ resolveDeviceTarget: async () => ({
24
+ ok: true,
25
+ target: {
26
+ platform: "android",
27
+ androidSerial: TARGET,
28
+ deviceName: "sdk_gphone64_arm64",
29
+ source: "adb-serial"
30
+ }
31
+ }),
32
+ formatResolverError: (e) => e.message
33
+ }));
34
+ jest.unstable_mockModule("../../pro/verifyAction.js", () => ({
35
+ captureScreenshot: async (platform, udid, deviceId) => {
36
+ verifyCalls.push({ fn: "captureScreenshot", platform, udid, deviceId });
37
+ return { buffer: Buffer.from("png"), width: 1080, height: 2400, scaleFactor: 1 };
38
+ },
39
+ verifyAndCapture: async (args) => {
40
+ verifyCalls.push({ fn: "verifyAndCapture", ...args });
41
+ return { screenshot: undefined, verification: undefined, afterWithMarkerBuffer: null };
42
+ },
43
+ burstCaptureAndVerify: async (args) => {
44
+ verifyCalls.push({ fn: "burstCaptureAndVerify", ...args });
45
+ return { screenshot: undefined, verification: undefined };
46
+ },
47
+ drawTapMarker: async (b) => b,
48
+ settleAndDiff: async () => null
49
+ }));
50
+ jest.unstable_mockModule("../../pro/overlayGuard.js", () => ({
51
+ checkOverlayBlocking: async () => null
52
+ }));
53
+ jest.unstable_mockModule("../../core/pressables.js", () => ({
54
+ pressElement: async () => ({
55
+ success: true,
56
+ result: JSON.stringify({
57
+ needsNativeTap: true,
58
+ nativeTapTarget: { x: 100, y: 200, unit: "points" },
59
+ pressed: "Button",
60
+ totalMatches: 1,
61
+ text: "Submit",
62
+ testID: "submit-btn",
63
+ path: "App > Button",
64
+ isInput: false
65
+ })
66
+ }),
67
+ findPressableElements: async () => ({ success: true, result: "[]" })
68
+ }));
69
+ const { tap } = await import("../../pro/tap.js");
70
+ const { connectedApps } = await import("../../core/state.js");
71
+ function connectAndroidApp() {
72
+ connectedApps.set("android-1", {
73
+ ws: { readyState: WebSocket.OPEN },
74
+ deviceInfo: {
75
+ id: "android-1",
76
+ title: "Hermes React Native",
77
+ description: "",
78
+ appId: "com.test",
79
+ type: "node",
80
+ webSocketDebuggerUrl: "ws://localhost:8081/android-1",
81
+ deviceName: "sdk_gphone64_arm64"
82
+ },
83
+ port: 8081,
84
+ platform: "android",
85
+ adbSerial: TARGET
86
+ });
87
+ }
88
+ function adbCallsMatching(fragment) {
89
+ return adbCalls.filter((args) => args.some((a) => a.includes(fragment)));
90
+ }
91
+ function targetsTheResolvedDevice(args) {
92
+ const i = args.indexOf("-s");
93
+ return i !== -1 && args[i + 1] === TARGET;
94
+ }
95
+ describe("tap threads the Android serial to the device", () => {
96
+ beforeEach(() => {
97
+ adbCalls.length = 0;
98
+ verifyCalls.length = 0;
99
+ connectedApps.clear();
100
+ });
101
+ it("sends a native coordinate tap to the resolved emulator, not the default one", async () => {
102
+ await tap({ x: 300, y: 600, native: true, device: TARGET, screenshot: false });
103
+ const taps = adbCallsMatching("input tap");
104
+ expect(taps).toHaveLength(1);
105
+ expect(targetsTheResolvedDevice(taps[0])).toBe(true);
106
+ });
107
+ it("captures the verification frames from the resolved emulator", async () => {
108
+ await tap({ x: 300, y: 600, native: true, device: TARGET, screenshot: false });
109
+ expect(verifyCalls.length).toBeGreaterThan(0);
110
+ for (const call of verifyCalls) {
111
+ expect(call.deviceId).toBe(TARGET);
112
+ }
113
+ });
114
+ it("sends a fiber-resolved tap to the resolved emulator", async () => {
115
+ connectAndroidApp();
116
+ await tap({ testID: "submit-btn", device: TARGET, screenshot: false, verify: false });
117
+ const taps = adbCallsMatching("input tap");
118
+ expect(taps).toHaveLength(1);
119
+ expect(targetsTheResolvedDevice(taps[0])).toBe(true);
120
+ const density = adbCallsMatching("wm density");
121
+ expect(density.length).toBeGreaterThan(0);
122
+ expect(density.every(targetsTheResolvedDevice)).toBe(true);
123
+ });
124
+ it("dumps the accessibility tree from the resolved emulator", async () => {
125
+ connectAndroidApp();
126
+ await tap({
127
+ text: "Submit",
128
+ device: TARGET,
129
+ strategy: "accessibility",
130
+ screenshot: false,
131
+ verify: false
132
+ });
133
+ const dumps = adbCallsMatching("uiautomator dump");
134
+ expect(dumps.length).toBeGreaterThan(0);
135
+ expect(dumps.every(targetsTheResolvedDevice)).toBe(true);
136
+ });
137
+ it("screenshots the resolved emulator for OCR", async () => {
138
+ connectAndroidApp();
139
+ await tap({
140
+ text: "Submit",
141
+ device: TARGET,
142
+ strategy: "ocr",
143
+ screenshot: false,
144
+ verify: false
145
+ });
146
+ const caps = adbCallsMatching("screencap");
147
+ expect(caps.length).toBeGreaterThan(0);
148
+ expect(caps.every(targetsTheResolvedDevice)).toBe(true);
149
+ });
150
+ it("leaves adb on its default device when no device is named", async () => {
151
+ await tap({ x: 300, y: 600, native: true, screenshot: false, verify: false });
152
+ const version = adbCalls.filter((args) => args[0] === "version");
153
+ expect(version.every((args) => !args.includes("-s"))).toBe(true);
154
+ });
155
+ });
156
+ describe("swipe verification frames come from the resolved emulator", () => {
157
+ beforeEach(() => {
158
+ adbCalls.length = 0;
159
+ verifyCalls.length = 0;
160
+ connectedApps.clear();
161
+ });
162
+ it("captures before/after frames from the target, not adb's default", async () => {
163
+ const handlers = new Map();
164
+ jest.unstable_mockModule("../../core/register.js", () => ({
165
+ registerToolWithTelemetry: (_s, name, _c, handler) => {
166
+ handlers.set(name, handler);
167
+ },
168
+ toolRegistry: new Map()
169
+ }));
170
+ const { registerInteractionTools } = await import("../../tools/interactionTools.js");
171
+ registerInteractionTools({ registerTool: () => { } });
172
+ await handlers.get("swipe")({ direction: "up", device: TARGET, screenshot: false });
173
+ expect(verifyCalls.length).toBeGreaterThan(0);
174
+ for (const call of verifyCalls) {
175
+ expect(call.deviceId).toBe(TARGET);
176
+ }
177
+ });
178
+ });
179
+ //# sourceMappingURL=tapAndroidSerial.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapAndroidSerial.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/tapAndroidSerial.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tapDuration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapDuration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/tapDuration.test.ts"],"names":[],"mappings":""}