react-native-ai-debugger 1.1.4 → 1.4.21
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 +12 -1
- package/README.md +198 -1063
- package/build/__tests__/helpers/tap-test-helpers.d.ts +36 -0
- package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -0
- package/build/__tests__/helpers/tap-test-helpers.js +130 -0
- package/build/__tests__/helpers/tap-test-helpers.js.map +1 -0
- package/build/__tests__/integration/connection-health.test.js +12 -6
- package/build/__tests__/integration/connection-health.test.js.map +1 -1
- package/build/__tests__/integration/execute-in-app.test.js +2 -1
- package/build/__tests__/integration/execute-in-app.test.js.map +1 -1
- package/build/__tests__/integration/tap-strategies.test.d.ts +2 -0
- package/build/__tests__/integration/tap-strategies.test.d.ts.map +1 -0
- package/build/__tests__/integration/tap-strategies.test.js +329 -0
- package/build/__tests__/integration/tap-strategies.test.js.map +1 -0
- package/build/__tests__/integration/tools.test.js +9 -10
- package/build/__tests__/integration/tools.test.js.map +1 -1
- package/build/__tests__/unit/burst.test.d.ts +2 -0
- package/build/__tests__/unit/burst.test.d.ts.map +1 -0
- package/build/__tests__/unit/burst.test.js +50 -0
- package/build/__tests__/unit/burst.test.js.map +1 -0
- package/build/__tests__/unit/connection-health.test.js +26 -16
- package/build/__tests__/unit/connection-health.test.js.map +1 -1
- package/build/__tests__/unit/fingerprint.test.d.ts +2 -0
- package/build/__tests__/unit/fingerprint.test.d.ts.map +1 -0
- package/build/__tests__/unit/fingerprint.test.js +89 -0
- package/build/__tests__/unit/fingerprint.test.js.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts +2 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.js +128 -0
- package/build/__tests__/unit/imageBuffer.test.js.map +1 -0
- package/build/__tests__/unit/logs.test.js +9 -0
- package/build/__tests__/unit/logs.test.js.map +1 -1
- package/build/__tests__/unit/networkInterceptor.test.d.ts +2 -0
- package/build/__tests__/unit/networkInterceptor.test.d.ts.map +1 -0
- package/build/__tests__/unit/networkInterceptor.test.js +104 -0
- package/build/__tests__/unit/networkInterceptor.test.js.map +1 -0
- package/build/__tests__/unit/screenshot-diff.test.d.ts +2 -0
- package/build/__tests__/unit/screenshot-diff.test.d.ts.map +1 -0
- package/build/__tests__/unit/screenshot-diff.test.js +97 -0
- package/build/__tests__/unit/screenshot-diff.test.js.map +1 -0
- package/build/__tests__/unit/tap.test.js +433 -28
- package/build/__tests__/unit/tap.test.js.map +1 -1
- package/build/core/android.d.ts.map +1 -1
- package/build/core/android.js +64 -29
- package/build/core/android.js.map +1 -1
- package/build/core/appDetection.d.ts +8 -0
- package/build/core/appDetection.d.ts.map +1 -0
- package/build/core/appDetection.js +91 -0
- package/build/core/appDetection.js.map +1 -0
- package/build/core/bundle.d.ts.map +1 -1
- package/build/core/bundle.js +15 -23
- package/build/core/bundle.js.map +1 -1
- package/build/core/config.d.ts +8 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +27 -0
- package/build/core/config.js.map +1 -0
- package/build/core/connection.d.ts +47 -3
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +519 -124
- package/build/core/connection.js.map +1 -1
- package/build/core/executor.d.ts +57 -14
- package/build/core/executor.d.ts.map +1 -1
- package/build/core/executor.js +936 -208
- package/build/core/executor.js.map +1 -1
- package/build/core/fingerprint.d.ts +4 -0
- package/build/core/fingerprint.d.ts.map +1 -0
- package/build/core/fingerprint.js +47 -0
- package/build/core/fingerprint.js.map +1 -0
- package/build/core/guides.d.ts.map +1 -1
- package/build/core/guides.js +48 -9
- package/build/core/guides.js.map +1 -1
- package/build/core/httpServer.js.map +1 -1
- package/build/core/imageBuffer.d.ts +37 -0
- package/build/core/imageBuffer.d.ts.map +1 -0
- package/build/core/imageBuffer.js +58 -0
- package/build/core/imageBuffer.js.map +1 -0
- package/build/core/index.d.ts +21 -17
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +21 -19
- package/build/core/index.js.map +1 -1
- package/build/core/ios.d.ts +36 -7
- package/build/core/ios.d.ts.map +1 -1
- package/build/core/ios.js +553 -323
- package/build/core/ios.js.map +1 -1
- package/build/core/license.d.ts +38 -0
- package/build/core/license.d.ts.map +1 -0
- package/build/core/license.js +265 -0
- package/build/core/license.js.map +1 -0
- package/build/core/logbox.d.ts +51 -0
- package/build/core/logbox.d.ts.map +1 -0
- package/build/core/logbox.js +258 -0
- package/build/core/logbox.js.map +1 -0
- package/build/core/logs.d.ts +1 -0
- package/build/core/logs.d.ts.map +1 -1
- package/build/core/logs.js +5 -0
- package/build/core/logs.js.map +1 -1
- package/build/core/metro.d.ts +8 -0
- package/build/core/metro.d.ts.map +1 -1
- package/build/core/metro.js +28 -0
- package/build/core/metro.js.map +1 -1
- package/build/core/networkInterceptor.d.ts +30 -0
- package/build/core/networkInterceptor.d.ts.map +1 -0
- package/build/core/networkInterceptor.js +207 -0
- package/build/core/networkInterceptor.js.map +1 -0
- package/build/core/ocr.d.ts +8 -3
- package/build/core/ocr.d.ts.map +1 -1
- package/build/core/ocr.js +116 -15
- package/build/core/ocr.js.map +1 -1
- package/build/core/posthog.d.ts +5 -0
- package/build/core/posthog.d.ts.map +1 -0
- package/build/core/posthog.js +46 -0
- package/build/core/posthog.js.map +1 -0
- package/build/core/sdkBridge.d.ts +67 -0
- package/build/core/sdkBridge.d.ts.map +1 -0
- package/build/core/sdkBridge.js +148 -0
- package/build/core/sdkBridge.js.map +1 -0
- package/build/core/state.d.ts +26 -5
- package/build/core/state.d.ts.map +1 -1
- package/build/core/state.js +83 -10
- package/build/core/state.js.map +1 -1
- package/build/core/telemetry.d.ts +19 -1
- package/build/core/telemetry.d.ts.map +1 -1
- package/build/core/telemetry.js +165 -8
- package/build/core/telemetry.js.map +1 -1
- package/build/core/types.d.ts +11 -0
- package/build/core/types.d.ts.map +1 -1
- package/build/index.js +1304 -304
- package/build/index.js.map +1 -1
- package/build/pro/screenshot-diff.d.ts +10 -0
- package/build/pro/screenshot-diff.d.ts.map +1 -0
- package/build/pro/screenshot-diff.js +38 -0
- package/build/pro/screenshot-diff.js.map +1 -0
- package/build/pro/tap.d.ts +160 -0
- package/build/pro/tap.d.ts.map +1 -0
- package/build/pro/tap.js +1215 -0
- package/build/pro/tap.js.map +1 -0
- package/build/tools/accountTools.d.ts +44 -0
- package/build/tools/accountTools.d.ts.map +1 -0
- package/build/tools/accountTools.js +217 -0
- package/build/tools/accountTools.js.map +1 -0
- package/package.json +11 -8
- package/build/core/httpServer.js +0 -2459
- package/build/core/httpServerProcess.js +0 -153
- package/build/httpServerStandalone.js +0 -31
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TapResult } from "../../pro/tap.js";
|
|
2
|
+
export type Platform = "ios" | "android";
|
|
3
|
+
/**
|
|
4
|
+
* Detect which platform is available by checking for booted simulators/emulators.
|
|
5
|
+
* Returns the first available platform.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectPlatform(): Promise<Platform>;
|
|
8
|
+
/**
|
|
9
|
+
* Connect to Metro and return the platform of the connected device.
|
|
10
|
+
*/
|
|
11
|
+
export declare function connectToMetro(): Promise<Platform>;
|
|
12
|
+
/**
|
|
13
|
+
* Disconnect all apps and clean up state.
|
|
14
|
+
*/
|
|
15
|
+
export declare function disconnectAll(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Read the test app's global state to verify a tap was registered.
|
|
18
|
+
* Returns { tapCount, lastTapped } or null if not available.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readTestState(): Promise<{
|
|
21
|
+
tapCount: number;
|
|
22
|
+
lastTapped: string;
|
|
23
|
+
} | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Reset the test app's tap counter and last-tapped state.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resetTestState(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Assert that a tap result succeeded and the test app registered the tap on the expected element.
|
|
30
|
+
*/
|
|
31
|
+
export declare function assertTapWorked(result: TapResult, expectedElement: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Wait for a short duration (ms) to let UI settle.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
36
|
+
//# sourceMappingURL=tap-test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-test-helpers.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/tap-test-helpers.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAEzC;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,QAAQ,CAAC,CAYxD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,QAAQ,CAAC,CA+BxD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBnD;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAU9F;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/F;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/__tests__/helpers/tap-test-helpers.ts
|
|
2
|
+
import { scanMetroPorts, fetchDevices, selectMainDevice } from "../../core/metro.js";
|
|
3
|
+
import { connectToDevice } from "../../core/connection.js";
|
|
4
|
+
import { executeInApp } from "../../core/executor.js";
|
|
5
|
+
import { connectedApps, pendingExecutions } from "../../core/state.js";
|
|
6
|
+
import { cancelAllReconnectionTimers, clearAllConnectionState } from "../../core/connectionState.js";
|
|
7
|
+
/**
|
|
8
|
+
* Detect which platform is available by checking for booted simulators/emulators.
|
|
9
|
+
* Returns the first available platform.
|
|
10
|
+
*/
|
|
11
|
+
export async function detectPlatform() {
|
|
12
|
+
const { execSync } = await import("child_process");
|
|
13
|
+
try {
|
|
14
|
+
const result = execSync("xcrun simctl list devices booted 2>/dev/null", { encoding: "utf-8" });
|
|
15
|
+
if (result.includes("Booted"))
|
|
16
|
+
return "ios";
|
|
17
|
+
}
|
|
18
|
+
catch { /* no iOS */ }
|
|
19
|
+
try {
|
|
20
|
+
const result = execSync("adb devices 2>/dev/null", { encoding: "utf-8" });
|
|
21
|
+
const lines = result.trim().split("\n").filter(l => l.includes("device") && !l.includes("List"));
|
|
22
|
+
if (lines.length > 0)
|
|
23
|
+
return "android";
|
|
24
|
+
}
|
|
25
|
+
catch { /* no Android */ }
|
|
26
|
+
throw new Error("No booted iOS simulator or Android emulator found");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Connect to Metro and return the platform of the connected device.
|
|
30
|
+
*/
|
|
31
|
+
export async function connectToMetro() {
|
|
32
|
+
const ports = await scanMetroPorts();
|
|
33
|
+
if (ports.length === 0) {
|
|
34
|
+
throw new Error("No Metro bundler found. Start Metro with the test app first.");
|
|
35
|
+
}
|
|
36
|
+
for (const port of ports) {
|
|
37
|
+
const devices = await fetchDevices(port);
|
|
38
|
+
const main = selectMainDevice(devices);
|
|
39
|
+
if (main) {
|
|
40
|
+
await connectToDevice(main, port, {
|
|
41
|
+
reconnectionConfig: {
|
|
42
|
+
enabled: false,
|
|
43
|
+
maxAttempts: 0,
|
|
44
|
+
initialDelayMs: 0,
|
|
45
|
+
maxDelayMs: 0,
|
|
46
|
+
backoffMultiplier: 1,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
// connectToDevice resolves with a message string, not the map key.
|
|
50
|
+
// Wait briefly for the async platform detection (findSimulatorByName)
|
|
51
|
+
// to complete, then read the first connected app's platform.
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
53
|
+
for (const app of connectedApps.values()) {
|
|
54
|
+
if (app.platform)
|
|
55
|
+
return app.platform;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error("Connected to Metro but could not determine platform");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Disconnect all apps and clean up state.
|
|
63
|
+
*/
|
|
64
|
+
export async function disconnectAll() {
|
|
65
|
+
const closePromises = [];
|
|
66
|
+
for (const [key, app] of connectedApps.entries()) {
|
|
67
|
+
closePromises.push(new Promise((resolve) => {
|
|
68
|
+
if (app.ws.readyState === app.ws.CLOSED) {
|
|
69
|
+
resolve();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
app.ws.on("close", () => resolve());
|
|
73
|
+
try {
|
|
74
|
+
app.ws.close();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
resolve();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
connectedApps.delete(key);
|
|
82
|
+
}
|
|
83
|
+
await Promise.all(closePromises);
|
|
84
|
+
pendingExecutions.clear();
|
|
85
|
+
cancelAllReconnectionTimers();
|
|
86
|
+
clearAllConnectionState();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read the test app's global state to verify a tap was registered.
|
|
90
|
+
* Returns { tapCount, lastTapped } or null if not available.
|
|
91
|
+
*/
|
|
92
|
+
export async function readTestState() {
|
|
93
|
+
const result = await executeInApp("JSON.stringify({ tapCount: global.__TEST_STATE__?.tapCount ?? -1, lastTapped: global.__TEST_STATE__?.lastTapped ?? 'unknown' })");
|
|
94
|
+
if (!result.success || !result.result)
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(result.result);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Reset the test app's tap counter and last-tapped state.
|
|
105
|
+
*/
|
|
106
|
+
export async function resetTestState() {
|
|
107
|
+
await executeInApp("global.__TEST_STATE__?.reset?.()");
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Assert that a tap result succeeded and the test app registered the tap on the expected element.
|
|
111
|
+
*/
|
|
112
|
+
export async function assertTapWorked(result, expectedElement) {
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
throw new Error(`Tap failed: ${result.error ?? result.suggestion ?? "unknown reason"}`);
|
|
115
|
+
}
|
|
116
|
+
const state = await readTestState();
|
|
117
|
+
if (!state) {
|
|
118
|
+
throw new Error("Could not read test app state via execute_in_app");
|
|
119
|
+
}
|
|
120
|
+
if (state.lastTapped !== expectedElement) {
|
|
121
|
+
throw new Error(`Expected lastTapped="${expectedElement}" but got "${state.lastTapped}"`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Wait for a short duration (ms) to let UI settle.
|
|
126
|
+
*/
|
|
127
|
+
export function sleep(ms) {
|
|
128
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=tap-test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-test-helpers.js","sourceRoot":"","sources":["../../../src/__tests__/helpers/tap-test-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jest, describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from "@jest/globals";
|
|
2
2
|
import { connectToDevice } from "../../core/connection.js";
|
|
3
3
|
import { checkAndEnsureConnection, getPassiveConnectionStatus } from "../../core/connection.js";
|
|
4
|
-
import { connectedApps, pendingExecutions, updateLastCDPMessageTime } from "../../core/state.js";
|
|
4
|
+
import { connectedApps, pendingExecutions, updateLastCDPMessageTime, clearAllCDPMessageTimes } from "../../core/state.js";
|
|
5
5
|
import { FakeCDPServer } from "../helpers/fake-cdp-server.js";
|
|
6
6
|
describe("Connection health (integration)", () => {
|
|
7
7
|
let server;
|
|
@@ -20,7 +20,7 @@ describe("Connection health (integration)", () => {
|
|
|
20
20
|
connectedApps.delete(key);
|
|
21
21
|
}
|
|
22
22
|
pendingExecutions.clear();
|
|
23
|
-
|
|
23
|
+
clearAllCDPMessageTimes();
|
|
24
24
|
});
|
|
25
25
|
afterEach(async () => {
|
|
26
26
|
const closePromises = [];
|
|
@@ -68,7 +68,7 @@ describe("Connection health (integration)", () => {
|
|
|
68
68
|
reconnectionConfig: { enabled: false, maxAttempts: 0, initialDelayMs: 0, maxDelayMs: 0, backoffMultiplier: 1 },
|
|
69
69
|
});
|
|
70
70
|
// Simulate recent CDP activity
|
|
71
|
-
updateLastCDPMessageTime(new Date());
|
|
71
|
+
updateLastCDPMessageTime(`${port}-test-device`, new Date());
|
|
72
72
|
const status = getPassiveConnectionStatus();
|
|
73
73
|
expect(status.connected).toBe(true);
|
|
74
74
|
expect(status.reason).toBe("ok");
|
|
@@ -89,12 +89,18 @@ describe("Connection health (integration)", () => {
|
|
|
89
89
|
reconnectionConfig: { enabled: false, maxAttempts: 0, initialDelayMs: 0, maxDelayMs: 0, backoffMultiplier: 1 },
|
|
90
90
|
});
|
|
91
91
|
// Set last activity to 60 seconds ago
|
|
92
|
-
updateLastCDPMessageTime(new Date(Date.now() - 60_000));
|
|
92
|
+
updateLastCDPMessageTime(`${port}-test-device`, new Date(Date.now() - 60_000));
|
|
93
93
|
const status = getPassiveConnectionStatus();
|
|
94
94
|
expect(status.connected).toBe(true);
|
|
95
95
|
expect(status.needsPing).toBe(true);
|
|
96
96
|
expect(status.reason).toBe("activity_stale");
|
|
97
97
|
});
|
|
98
|
+
it("checks specific device when appKey is provided", () => {
|
|
99
|
+
// With no connections, should return no_connection regardless of appKey
|
|
100
|
+
const result = getPassiveConnectionStatus("8081-somedevice");
|
|
101
|
+
expect(result.connected).toBe(false);
|
|
102
|
+
expect(result.reason).toBe("no_connection");
|
|
103
|
+
});
|
|
98
104
|
it("returns no_activity when connected but no CDP messages ever received", async () => {
|
|
99
105
|
server = new FakeCDPServer();
|
|
100
106
|
const port = await server.start();
|
|
@@ -112,7 +118,7 @@ describe("Connection health (integration)", () => {
|
|
|
112
118
|
});
|
|
113
119
|
// Note: handleCDPMessage will fire for enable responses, which updates timestamp
|
|
114
120
|
// Reset it to null to simulate the "never received" case
|
|
115
|
-
|
|
121
|
+
clearAllCDPMessageTimes();
|
|
116
122
|
const status = getPassiveConnectionStatus();
|
|
117
123
|
expect(status.connected).toBe(false);
|
|
118
124
|
expect(status.reason).toBe("no_activity");
|
|
@@ -140,7 +146,7 @@ describe("Connection health (integration)", () => {
|
|
|
140
146
|
await connectToDevice(device, port, {
|
|
141
147
|
reconnectionConfig: { enabled: false, maxAttempts: 0, initialDelayMs: 0, maxDelayMs: 0, backoffMultiplier: 1 },
|
|
142
148
|
});
|
|
143
|
-
updateLastCDPMessageTime(new Date());
|
|
149
|
+
updateLastCDPMessageTime(`${port}-test-device`, new Date());
|
|
144
150
|
const result = await checkAndEnsureConnection();
|
|
145
151
|
expect(result.connected).toBe(true);
|
|
146
152
|
expect(result.wasReconnected).toBe(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-health.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/connection-health.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"connection-health.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/connection-health.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -93,7 +93,8 @@ describe("executeInApp (integration)", () => {
|
|
|
93
93
|
it("sends expression with global polyfill prepended", async () => {
|
|
94
94
|
server.respondWithValue(true, "boolean");
|
|
95
95
|
await executeInApp("__DEV__", false, { timeoutMs: 5000 });
|
|
96
|
-
const evalMsg = server.receivedMessages.find((m) => m.method === "Runtime.evaluate"
|
|
96
|
+
const evalMsg = server.receivedMessages.find((m) => m.method === "Runtime.evaluate" &&
|
|
97
|
+
m.params.expression.includes("__DEV__"));
|
|
97
98
|
expect(evalMsg).toBeDefined();
|
|
98
99
|
const expr = evalMsg.params.expression;
|
|
99
100
|
expect(expr).toContain("var global");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute-in-app.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/execute-in-app.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"execute-in-app.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/execute-in-app.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-strategies.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/tap-strategies.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// src/__tests__/integration/tap-strategies.test.ts
|
|
2
|
+
import { describe, it, expect, beforeAll, afterAll, afterEach } from "@jest/globals";
|
|
3
|
+
import { tap } from "../../pro/tap.js";
|
|
4
|
+
import { connectToMetro, disconnectAll, resetTestState, readTestState, assertTapWorked, sleep, } from "../helpers/tap-test-helpers.js";
|
|
5
|
+
let platform;
|
|
6
|
+
beforeAll(async () => {
|
|
7
|
+
platform = await connectToMetro();
|
|
8
|
+
}, 30000);
|
|
9
|
+
afterAll(async () => {
|
|
10
|
+
await disconnectAll();
|
|
11
|
+
}, 10000);
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await resetTestState();
|
|
14
|
+
await sleep(500);
|
|
15
|
+
}, 10000);
|
|
16
|
+
describe("Category 1: RN Fiber & JS Strategies", () => {
|
|
17
|
+
it("tap button by testID (auto strategy)", async () => {
|
|
18
|
+
const result = await tap({ testID: "submit-btn" });
|
|
19
|
+
await assertTapWorked(result, "submit-btn");
|
|
20
|
+
}, 30000);
|
|
21
|
+
it("tap button by visible text (auto strategy)", async () => {
|
|
22
|
+
const result = await tap({ text: "Cancel" });
|
|
23
|
+
await assertTapWorked(result, "cancel-btn");
|
|
24
|
+
}, 30000);
|
|
25
|
+
it("tap icon-only button by component name", async () => {
|
|
26
|
+
const result = await tap({ component: "HeartIcon" });
|
|
27
|
+
await assertTapWorked(result, "heart-btn");
|
|
28
|
+
}, 30000);
|
|
29
|
+
it("tap by text with explicit fiber strategy", async () => {
|
|
30
|
+
const result = await tap({ text: "Submit", strategy: "fiber" });
|
|
31
|
+
await assertTapWorked(result, "submit-btn");
|
|
32
|
+
}, 30000);
|
|
33
|
+
it("tap by testID with explicit accessibility strategy", async () => {
|
|
34
|
+
const result = await tap({ testID: "submit-btn", strategy: "accessibility" });
|
|
35
|
+
await assertTapWorked(result, "submit-btn");
|
|
36
|
+
}, 30000);
|
|
37
|
+
it("tap by text with explicit OCR strategy", async () => {
|
|
38
|
+
const result = await tap({ text: "Submit", strategy: "ocr" });
|
|
39
|
+
await assertTapWorked(result, "submit-btn");
|
|
40
|
+
}, 30000);
|
|
41
|
+
it("focus TextInput by testID", async () => {
|
|
42
|
+
const result = await tap({ testID: "name-input" });
|
|
43
|
+
expect(result.success).toBe(true);
|
|
44
|
+
// TextInput has onChangeText, not onPress — fiber detects this and falls
|
|
45
|
+
// through to native tap for focus. No tap counter increment expected since
|
|
46
|
+
// the test app only counts onPress handlers, not input focus events.
|
|
47
|
+
expect(result.method).toBeDefined();
|
|
48
|
+
}, 30000);
|
|
49
|
+
it("tap Cyrillic text button", async () => {
|
|
50
|
+
const result = await tap({ text: "Отправить" });
|
|
51
|
+
await assertTapWorked(result, "cyrillic-btn");
|
|
52
|
+
}, 30000);
|
|
53
|
+
it("tap CJK text button", async () => {
|
|
54
|
+
const result = await tap({ text: "送信" });
|
|
55
|
+
await assertTapWorked(result, "cjk-btn");
|
|
56
|
+
}, 30000);
|
|
57
|
+
it("tap emoji text button (should skip fiber, use accessibility or OCR)", async () => {
|
|
58
|
+
const result = await tap({ text: "🔥 Fire" });
|
|
59
|
+
await assertTapWorked(result, "emoji-btn");
|
|
60
|
+
// Fiber can't handle emoji — should fall back to accessibility or OCR
|
|
61
|
+
expect(result.method).not.toBe("fiber");
|
|
62
|
+
}, 30000);
|
|
63
|
+
it("tap second duplicate-text button using index parameter", async () => {
|
|
64
|
+
const result = await tap({ text: "Action", index: 1 });
|
|
65
|
+
await assertTapWorked(result, "action-btn-2");
|
|
66
|
+
}, 30000);
|
|
67
|
+
it("tap first duplicate-text button using index=0", async () => {
|
|
68
|
+
const result = await tap({ text: "Action", index: 0 });
|
|
69
|
+
await assertTapWorked(result, "action-btn-1");
|
|
70
|
+
}, 30000);
|
|
71
|
+
it("focus email TextInput by testID", async () => {
|
|
72
|
+
const result = await tap({ testID: "email-input" });
|
|
73
|
+
expect(result.success).toBe(true);
|
|
74
|
+
expect(result.method).toBeDefined();
|
|
75
|
+
}, 30000);
|
|
76
|
+
it("tap button using testID + text combined", async () => {
|
|
77
|
+
const result = await tap({ testID: "submit-btn", text: "Submit" });
|
|
78
|
+
await assertTapWorked(result, "submit-btn");
|
|
79
|
+
}, 30000);
|
|
80
|
+
});
|
|
81
|
+
describe("Category 2: RN Coordinates & Verification", () => {
|
|
82
|
+
it("tap by pixel coordinates", async () => {
|
|
83
|
+
// First, tap by testID to find the element's coordinates.
|
|
84
|
+
// tappedAt returns coordinates in the native unit used by the platform
|
|
85
|
+
// (points on iOS, pixels on Android). tap({ x, y }) treats these as
|
|
86
|
+
// screenshot pixel coordinates and applies conversion internally.
|
|
87
|
+
const findResult = await tap({ testID: "submit-btn", screenshot: true });
|
|
88
|
+
expect(findResult.success).toBe(true);
|
|
89
|
+
expect(findResult.tappedAt).toBeDefined();
|
|
90
|
+
await resetTestState();
|
|
91
|
+
await sleep(500);
|
|
92
|
+
const { x, y } = findResult.tappedAt;
|
|
93
|
+
const result = await tap({ x, y });
|
|
94
|
+
await assertTapWorked(result, "submit-btn");
|
|
95
|
+
expect(result.method).toBe("coordinate");
|
|
96
|
+
}, 30000);
|
|
97
|
+
it("tap with native=true at coordinates", async () => {
|
|
98
|
+
// Get coordinates from a known element
|
|
99
|
+
const findResult = await tap({ testID: "cancel-btn", screenshot: true });
|
|
100
|
+
expect(findResult.success).toBe(true);
|
|
101
|
+
expect(findResult.tappedAt).toBeDefined();
|
|
102
|
+
await resetTestState();
|
|
103
|
+
await sleep(500);
|
|
104
|
+
const { x, y } = findResult.tappedAt;
|
|
105
|
+
const result = await tap({ x, y, native: true });
|
|
106
|
+
expect(result.success).toBe(true);
|
|
107
|
+
// Native tap bypasses RN, verify via test state
|
|
108
|
+
const state = await readTestState();
|
|
109
|
+
expect(state?.lastTapped).toBe("cancel-btn");
|
|
110
|
+
}, 30000);
|
|
111
|
+
it("tap with screenshot verification", async () => {
|
|
112
|
+
const result = await tap({ testID: "submit-btn", verify: true, screenshot: true });
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
expect(result.screenshot).toBeDefined();
|
|
115
|
+
expect(result.screenshot?.image).toBeTruthy();
|
|
116
|
+
expect(result.verification).toBeDefined();
|
|
117
|
+
expect(result.verification?.meaningful).toBe(true);
|
|
118
|
+
}, 30000);
|
|
119
|
+
it("tap with screenshot=false", async () => {
|
|
120
|
+
const result = await tap({ testID: "submit-btn", screenshot: false });
|
|
121
|
+
expect(result.success).toBe(true);
|
|
122
|
+
expect(result.screenshot).toBeUndefined();
|
|
123
|
+
}, 30000);
|
|
124
|
+
it("tap non-existent element returns failure with suggestion", async () => {
|
|
125
|
+
const result = await tap({ text: "DoesNotExist" });
|
|
126
|
+
expect(result.success).toBe(false);
|
|
127
|
+
expect(result.suggestion).toBeTruthy();
|
|
128
|
+
expect(result.attempted).toBeDefined();
|
|
129
|
+
expect(result.attempted.length).toBeGreaterThan(0);
|
|
130
|
+
}, 30000);
|
|
131
|
+
it("tap completes within timeout budget", async () => {
|
|
132
|
+
const start = Date.now();
|
|
133
|
+
const result = await tap({ testID: "submit-btn" });
|
|
134
|
+
const elapsed = Date.now() - start;
|
|
135
|
+
expect(result.success).toBe(true);
|
|
136
|
+
// Successful tap should complete well under the 20s timeout
|
|
137
|
+
expect(elapsed).toBeLessThan(20000);
|
|
138
|
+
}, 30000);
|
|
139
|
+
it("failed tap respects timeout and does not hang", async () => {
|
|
140
|
+
const start = Date.now();
|
|
141
|
+
const result = await tap({ text: "DoesNotExist_Timeout_Test" });
|
|
142
|
+
const elapsed = Date.now() - start;
|
|
143
|
+
expect(result.success).toBe(false);
|
|
144
|
+
// Failed tap should not exceed ~20s budget (with some margin for cleanup)
|
|
145
|
+
expect(elapsed).toBeLessThan(25000);
|
|
146
|
+
// Check that attempted strategies report timeout/skip info
|
|
147
|
+
expect(result.attempted).toBeDefined();
|
|
148
|
+
expect(result.attempted.length).toBeGreaterThan(0);
|
|
149
|
+
}, 30000);
|
|
150
|
+
it("tap with burst verification mode", async () => {
|
|
151
|
+
const result = await tap({ testID: "submit-btn", verify: true, burst: true, screenshot: true });
|
|
152
|
+
expect(result.success).toBe(true);
|
|
153
|
+
expect(result.screenshot).toBeDefined();
|
|
154
|
+
expect(result.verification).toBeDefined();
|
|
155
|
+
// Burst mode should include transient detection fields
|
|
156
|
+
if (result.verification?.transientChangeDetected !== undefined) {
|
|
157
|
+
expect(typeof result.verification.transientChangeDetected).toBe("boolean");
|
|
158
|
+
}
|
|
159
|
+
}, 30000);
|
|
160
|
+
it("tap non-interactive area by testID returns failure or no state change", async () => {
|
|
161
|
+
// The disabled-area View has no onPress — fiber may find it but native
|
|
162
|
+
// tap won't trigger any handler. Verify test state doesn't change.
|
|
163
|
+
const stateBefore = await readTestState();
|
|
164
|
+
const result = await tap({ testID: "disabled-area" });
|
|
165
|
+
// Whether tap "succeeds" (accessibility finds it) or fails, test state shouldn't change
|
|
166
|
+
const stateAfter = await readTestState();
|
|
167
|
+
expect(stateAfter?.tapCount).toBe(stateBefore?.tapCount);
|
|
168
|
+
}, 30000);
|
|
169
|
+
it("tap navigation button and verify screen change", async () => {
|
|
170
|
+
const result = await tap({ testID: "nav-scroll-btn" });
|
|
171
|
+
expect(result.success).toBe(true);
|
|
172
|
+
await sleep(1000); // wait for navigation animation
|
|
173
|
+
// Verify we're on Screen 2 by checking for its elements
|
|
174
|
+
const backBtnResult = await tap({ testID: "nav-back-btn", screenshot: false });
|
|
175
|
+
expect(backBtnResult.success).toBe(true);
|
|
176
|
+
await sleep(500); // wait for navigation back
|
|
177
|
+
}, 30000);
|
|
178
|
+
it("scroll then tap bottom button", async () => {
|
|
179
|
+
// Navigate to scroll screen
|
|
180
|
+
await tap({ testID: "nav-scroll-btn" });
|
|
181
|
+
await sleep(1000);
|
|
182
|
+
// Swipe up to scroll down and reveal the bottom button
|
|
183
|
+
const { iosSwipe } = await import("../../core/ios.js");
|
|
184
|
+
const { androidSwipe } = await import("../../core/android.js");
|
|
185
|
+
// Perform multiple swipes to reach the bottom
|
|
186
|
+
for (let i = 0; i < 5; i++) {
|
|
187
|
+
if (platform === "ios") {
|
|
188
|
+
await iosSwipe(200, 600, 200, 200);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
await androidSwipe(540, 1500, 540, 500);
|
|
192
|
+
}
|
|
193
|
+
await sleep(500);
|
|
194
|
+
}
|
|
195
|
+
// Try to tap the bottom button
|
|
196
|
+
const result = await tap({ testID: "bottom-btn" });
|
|
197
|
+
await assertTapWorked(result, "bottom-btn");
|
|
198
|
+
// Navigate back
|
|
199
|
+
await tap({ testID: "nav-back-btn" });
|
|
200
|
+
await sleep(500);
|
|
201
|
+
}, 60000);
|
|
202
|
+
it("tap list item on scroll screen by testID", async () => {
|
|
203
|
+
// Navigate to scroll screen
|
|
204
|
+
await tap({ testID: "nav-scroll-btn" });
|
|
205
|
+
await sleep(1000);
|
|
206
|
+
// Tap a visible list item
|
|
207
|
+
const result = await tap({ testID: "list-item-1" });
|
|
208
|
+
expect(result.success).toBe(true);
|
|
209
|
+
// Navigate back
|
|
210
|
+
await tap({ testID: "nav-back-btn" });
|
|
211
|
+
await sleep(500);
|
|
212
|
+
}, 30000);
|
|
213
|
+
it("tap list item on scroll screen by text", async () => {
|
|
214
|
+
// Navigate to scroll screen
|
|
215
|
+
await tap({ testID: "nav-scroll-btn" });
|
|
216
|
+
await sleep(1000);
|
|
217
|
+
// Tap by visible text
|
|
218
|
+
const result = await tap({ text: "Item 1" });
|
|
219
|
+
expect(result.success).toBe(true);
|
|
220
|
+
// Navigate back
|
|
221
|
+
await tap({ testID: "nav-back-btn" });
|
|
222
|
+
await sleep(500);
|
|
223
|
+
}, 30000);
|
|
224
|
+
});
|
|
225
|
+
describe("Category 3: Non-RN Native App (System Apps)", () => {
|
|
226
|
+
const IOS_SETTINGS_BUNDLE = "com.apple.Preferences";
|
|
227
|
+
const ANDROID_SETTINGS_PACKAGE = "com.android.settings";
|
|
228
|
+
// Platform checks are inside it() bodies because platform is set in beforeAll,
|
|
229
|
+
// which runs after Jest collects describe blocks synchronously.
|
|
230
|
+
it("tap Settings item by text (iOS)", async () => {
|
|
231
|
+
if (platform !== "ios")
|
|
232
|
+
return;
|
|
233
|
+
const { iosLaunchApp } = await import("../../core/ios.js");
|
|
234
|
+
await iosLaunchApp(IOS_SETTINGS_BUNDLE);
|
|
235
|
+
await sleep(2000);
|
|
236
|
+
const result = await tap({ text: "General", native: true });
|
|
237
|
+
expect(result.success).toBe(true);
|
|
238
|
+
}, 30000);
|
|
239
|
+
it("tap by OCR on native app (iOS)", async () => {
|
|
240
|
+
if (platform !== "ios")
|
|
241
|
+
return;
|
|
242
|
+
const { iosLaunchApp } = await import("../../core/ios.js");
|
|
243
|
+
await iosLaunchApp(IOS_SETTINGS_BUNDLE);
|
|
244
|
+
await sleep(2000);
|
|
245
|
+
const result = await tap({ text: "General", strategy: "ocr", native: true });
|
|
246
|
+
expect(result.success).toBe(true);
|
|
247
|
+
expect(result.method).toBe("ocr");
|
|
248
|
+
}, 30000);
|
|
249
|
+
it("find and tap via iOS accessibility tree", async () => {
|
|
250
|
+
if (platform !== "ios")
|
|
251
|
+
return;
|
|
252
|
+
const { iosLaunchApp, iosFindElement } = await import("../../core/ios.js");
|
|
253
|
+
await iosLaunchApp(IOS_SETTINGS_BUNDLE);
|
|
254
|
+
await sleep(2000);
|
|
255
|
+
const findResult = await iosFindElement({ labelContains: "General" });
|
|
256
|
+
expect(findResult.success).toBe(true);
|
|
257
|
+
expect(findResult.found).toBe(true);
|
|
258
|
+
expect(findResult.element).toBeDefined();
|
|
259
|
+
const { x, y } = findResult.element.center;
|
|
260
|
+
const tapResult = await tap({ x, y, native: true });
|
|
261
|
+
expect(tapResult.success).toBe(true);
|
|
262
|
+
}, 30000);
|
|
263
|
+
it("tap Settings item by text (Android)", async () => {
|
|
264
|
+
if (platform !== "android")
|
|
265
|
+
return;
|
|
266
|
+
const { androidLaunchApp } = await import("../../core/android.js");
|
|
267
|
+
await androidLaunchApp(ANDROID_SETTINGS_PACKAGE);
|
|
268
|
+
await sleep(2000);
|
|
269
|
+
const result = await tap({ text: "Network", native: true });
|
|
270
|
+
expect(result.success).toBe(true);
|
|
271
|
+
}, 30000);
|
|
272
|
+
it("tap by OCR on native app (Android)", async () => {
|
|
273
|
+
if (platform !== "android")
|
|
274
|
+
return;
|
|
275
|
+
const { androidLaunchApp } = await import("../../core/android.js");
|
|
276
|
+
await androidLaunchApp(ANDROID_SETTINGS_PACKAGE);
|
|
277
|
+
await sleep(2000);
|
|
278
|
+
const result = await tap({ text: "Network", strategy: "ocr", native: true });
|
|
279
|
+
expect(result.success).toBe(true);
|
|
280
|
+
expect(result.method).toBe("ocr");
|
|
281
|
+
}, 30000);
|
|
282
|
+
it("find and tap via Android accessibility tree", async () => {
|
|
283
|
+
if (platform !== "android")
|
|
284
|
+
return;
|
|
285
|
+
const { androidLaunchApp, androidFindElement } = await import("../../core/android.js");
|
|
286
|
+
await androidLaunchApp(ANDROID_SETTINGS_PACKAGE);
|
|
287
|
+
await sleep(2000);
|
|
288
|
+
const findResult = await androidFindElement({ textContains: "Network" });
|
|
289
|
+
expect(findResult.success).toBe(true);
|
|
290
|
+
expect(findResult.found).toBe(true);
|
|
291
|
+
expect(findResult.element).toBeDefined();
|
|
292
|
+
const { x, y } = findResult.element.center;
|
|
293
|
+
const tapResult = await tap({ x, y, native: true });
|
|
294
|
+
expect(tapResult.success).toBe(true);
|
|
295
|
+
}, 30000);
|
|
296
|
+
it("tap by coordinates on native app", async () => {
|
|
297
|
+
if (platform === "ios") {
|
|
298
|
+
const { iosLaunchApp } = await import("../../core/ios.js");
|
|
299
|
+
await iosLaunchApp(IOS_SETTINGS_BUNDLE);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const { androidLaunchApp } = await import("../../core/android.js");
|
|
303
|
+
await androidLaunchApp(ANDROID_SETTINGS_PACKAGE);
|
|
304
|
+
}
|
|
305
|
+
await sleep(2000);
|
|
306
|
+
const targetText = platform === "ios" ? "General" : "Network";
|
|
307
|
+
const ocrResult = await tap({ text: targetText, strategy: "ocr", native: true });
|
|
308
|
+
expect(ocrResult.success).toBe(true);
|
|
309
|
+
expect(ocrResult.tappedAt).toBeDefined();
|
|
310
|
+
}, 30000);
|
|
311
|
+
it("tap without Metro connection (native only)", async () => {
|
|
312
|
+
await disconnectAll();
|
|
313
|
+
await sleep(1000);
|
|
314
|
+
if (platform === "ios") {
|
|
315
|
+
const { iosLaunchApp } = await import("../../core/ios.js");
|
|
316
|
+
await iosLaunchApp(IOS_SETTINGS_BUNDLE);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
const { androidLaunchApp } = await import("../../core/android.js");
|
|
320
|
+
await androidLaunchApp(ANDROID_SETTINGS_PACKAGE);
|
|
321
|
+
}
|
|
322
|
+
await sleep(2000);
|
|
323
|
+
const result = await tap({ x: 200, y: 400, native: true, platform });
|
|
324
|
+
expect(result.success).toBe(true);
|
|
325
|
+
// Reconnect for any subsequent test runs
|
|
326
|
+
await connectToMetro();
|
|
327
|
+
}, 30000);
|
|
328
|
+
});
|
|
329
|
+
//# sourceMappingURL=tap-strategies.test.js.map
|