mobile-debug-mcp 0.13.0 → 0.15.0
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/README.md +2 -2
- package/dist/android/interact.js +13 -1
- package/dist/android/observe.js +13 -0
- package/dist/cli/ios/run-ios-smoke.js +2 -2
- package/dist/cli/ios/run-ios-ui-tree-tap.js +2 -2
- package/dist/interact/android.js +91 -0
- package/dist/interact/index.js +37 -0
- package/dist/interact/ios.js +120 -0
- package/dist/interact/shared/fingerprint.js +72 -0
- package/dist/interact/shared/scroll_to_element.js +98 -0
- package/dist/ios/interact.js +52 -1
- package/dist/ios/observe.js +12 -0
- package/dist/manage/android.js +162 -0
- package/dist/manage/index.js +364 -0
- package/dist/manage/ios.js +353 -0
- package/dist/observe/android.js +351 -0
- package/dist/observe/fingerprint.js +1 -0
- package/dist/observe/index.js +85 -0
- package/dist/observe/ios.js +320 -0
- package/dist/observe/test/device/logstream-real.js +34 -0
- package/dist/observe/test/device/run-screen-fingerprint.js +29 -0
- package/dist/observe/test/device/run-scroll-test-android.js +22 -0
- package/dist/observe/test/device/test-ui-tree.js +67 -0
- package/dist/observe/test/device/wait_for_element_real.js +69 -0
- package/dist/observe/test/unit/get_screen_fingerprint.test.js +54 -0
- package/dist/observe/test/unit/logparse.test.js +39 -0
- package/dist/observe/test/unit/logstream.test.js +41 -0
- package/dist/observe/test/unit/scroll_to_element.test.js +113 -0
- package/dist/observe/test/unit/wait_for_element_mock.js +92 -0
- package/dist/server.js +54 -9
- package/dist/shared/fingerprint.js +72 -0
- package/dist/shared/scroll_to_element.js +98 -0
- package/dist/tools/interact.js +19 -22
- package/dist/tools/manage.js +2 -2
- package/dist/tools/observe.js +45 -43
- package/dist/tools/scroll_to_element.js +98 -0
- package/dist/utils/android/utils.js +429 -0
- package/dist/utils/cli/idb/check-idb.js +84 -0
- package/dist/utils/cli/idb/idb-helper.js +91 -0
- package/dist/utils/cli/idb/install-idb.js +82 -0
- package/dist/utils/cli/ios/preflight-ios.js +155 -0
- package/dist/utils/cli/ios/run-ios-smoke.js +28 -0
- package/dist/utils/cli/ios/run-ios-ui-tree-tap.js +29 -0
- package/dist/utils/diagnostics.js +1 -1
- package/dist/utils/ios/utils.js +301 -0
- package/dist/utils/resolve-device.js +2 -2
- package/docs/CHANGELOG.md +11 -0
- package/docs/tools/TOOLS.md +3 -3
- package/docs/tools/interact.md +31 -0
- package/docs/tools/observe.md +24 -0
- package/package.json +1 -1
- package/src/{android/interact.ts → interact/android.ts} +15 -2
- package/src/interact/index.ts +47 -0
- package/src/{ios/interact.ts → interact/ios.ts} +58 -3
- package/src/interact/shared/fingerprint.ts +73 -0
- package/src/interact/shared/scroll_to_element.ts +110 -0
- package/src/{android/manage.ts → manage/android.ts} +2 -2
- package/src/{tools/manage.ts → manage/index.ts} +7 -4
- package/src/{ios/manage.ts → manage/ios.ts} +1 -1
- package/src/{android/observe.ts → observe/android.ts} +14 -26
- package/src/observe/index.ts +92 -0
- package/src/{ios/observe.ts → observe/ios.ts} +17 -35
- package/src/server.ts +57 -10
- package/src/{android → utils/android}/utils.ts +2 -2
- package/src/{cli → utils/cli}/ios/run-ios-smoke.ts +2 -2
- package/src/{cli → utils/cli}/ios/run-ios-ui-tree-tap.ts +3 -3
- package/src/utils/diagnostics.ts +1 -1
- package/src/{ios → utils/ios}/utils.ts +2 -2
- package/src/utils/resolve-device.ts +2 -2
- package/test/{device/interact → interact/device}/smoke-test.ts +3 -4
- package/test/{device/manage → manage/device}/run-install-android.ts +1 -1
- package/test/{device/manage → manage/device}/run-install-ios.ts +1 -1
- package/test/{device/manage → manage/device}/run-install-kmp.ts +1 -1
- package/test/{unit/manage → manage/unit}/build.test.ts +1 -1
- package/test/{unit/manage → manage/unit}/build_and_install.test.ts +1 -1
- package/test/{unit/manage → manage/unit}/detection.test.ts +1 -1
- package/test/{unit/manage → manage/unit}/diagnostics.test.ts +2 -2
- package/test/{unit/manage → manage/unit}/install.test.ts +1 -1
- package/test/{unit/manage → manage/unit}/mcp_disable_autodetect.test.ts +1 -1
- package/test/{device/observe → observe/device}/logstream-real.ts +1 -1
- package/test/observe/device/run-screen-fingerprint.ts +36 -0
- package/test/observe/device/run-scroll-test-android.ts +24 -0
- package/test/{device/observe → observe/device}/test-ui-tree.ts +2 -2
- package/test/{device/observe → observe/device}/wait_for_element_real.ts +2 -2
- package/test/observe/unit/get_screen_fingerprint.test.ts +69 -0
- package/test/{unit/observe → observe/unit}/logparse.test.ts +1 -1
- package/test/{unit/observe → observe/unit}/logstream.test.ts +1 -1
- package/test/observe/unit/scroll_to_element.test.ts +129 -0
- package/test/{unit/observe → observe/unit}/wait_for_element_mock.ts +3 -3
- package/test/unit/index.ts +12 -11
- package/src/tools/interact.ts +0 -45
- package/src/tools/observe.ts +0 -82
- package/test/device/README.md +0 -49
- package/test/device/index.ts +0 -27
- package/test/device/utils/test-dist.ts +0 -41
- package/test/unit/utils/detect-java.test.ts +0 -22
- /package/src/{cli → utils/cli}/idb/check-idb.ts +0 -0
- /package/src/{cli → utils/cli}/idb/idb-helper.ts +0 -0
- /package/src/{cli → utils/cli}/idb/install-idb.ts +0 -0
- /package/src/{cli → utils/cli}/ios/preflight-ios.ts +0 -0
- /package/test/{device/interact → interact/device}/run-real-test.ts +0 -0
- /package/test/{device/manage → manage/device}/install.integration.ts +0 -0
- /package/test/{device/manage → manage/device}/run-build-install-ios.ts +0 -0
package/src/tools/observe.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { resolveTargetDevice } from '../utils/resolve-device.js'
|
|
2
|
-
import { AndroidObserve } from '../android/observe.js'
|
|
3
|
-
import { iOSObserve } from '../ios/observe.js'
|
|
4
|
-
|
|
5
|
-
export class ToolsObserve {
|
|
6
|
-
static async getUITreeHandler({ platform, deviceId }: { platform: 'android' | 'ios', deviceId?: string }) {
|
|
7
|
-
if (platform === 'android') {
|
|
8
|
-
const resolved = await resolveTargetDevice({ platform: 'android', deviceId })
|
|
9
|
-
return await new AndroidObserve().getUITree(resolved.id)
|
|
10
|
-
} else {
|
|
11
|
-
const resolved = await resolveTargetDevice({ platform: 'ios', deviceId })
|
|
12
|
-
return await new iOSObserve().getUITree(resolved.id)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static async getCurrentScreenHandler({ deviceId }: { deviceId?: string }) {
|
|
17
|
-
const resolved = await resolveTargetDevice({ platform: 'android', deviceId })
|
|
18
|
-
return await new AndroidObserve().getCurrentScreen(resolved.id)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
static async getLogsHandler({ platform, appId, deviceId, lines }: { platform: 'android' | 'ios', appId?: string, deviceId?: string, lines?: number }) {
|
|
22
|
-
if (platform === 'android') {
|
|
23
|
-
const resolved = await resolveTargetDevice({ platform: 'android', appId, deviceId })
|
|
24
|
-
const response = await new AndroidObserve().getLogs(appId, lines ?? 200, resolved.id)
|
|
25
|
-
const logs = Array.isArray(response.logs) ? response.logs : []
|
|
26
|
-
const crashLines = logs.filter(line => line.includes('FATAL EXCEPTION'))
|
|
27
|
-
return { device: response.device, logs, crashLines }
|
|
28
|
-
} else {
|
|
29
|
-
const resolved = await resolveTargetDevice({ platform: 'ios', appId, deviceId })
|
|
30
|
-
const resp = await new iOSObserve().getLogs(appId, resolved.id)
|
|
31
|
-
const logs = Array.isArray(resp.logs) ? resp.logs : []
|
|
32
|
-
const crashLines = logs.filter(l => l.includes('FATAL EXCEPTION'))
|
|
33
|
-
return { device: resp.device, logs, crashLines }
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static async startLogStreamHandler({ platform, packageName, level, sessionId, deviceId }: { platform?: 'android' | 'ios', packageName: string, level?: 'error' | 'warn' | 'info' | 'debug', sessionId?: string, deviceId?: string }) {
|
|
38
|
-
const effectivePlatform = platform || 'android'
|
|
39
|
-
const sid = sessionId || 'default'
|
|
40
|
-
if (effectivePlatform === 'android') {
|
|
41
|
-
const resolved = await resolveTargetDevice({ platform: 'android', appId: packageName, deviceId })
|
|
42
|
-
// Delegate to AndroidObserve's log stream methods
|
|
43
|
-
return await new AndroidObserve().startLogStream(packageName, level || 'error', resolved.id, sid)
|
|
44
|
-
} else {
|
|
45
|
-
const resolved = await resolveTargetDevice({ platform: 'ios', appId: packageName, deviceId })
|
|
46
|
-
// Delegate to iOSObserve for starting log streams
|
|
47
|
-
return await new iOSObserve().startLogStream(packageName, resolved.id, sid)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
static async readLogStreamHandler({ platform, sessionId, limit, since }: { platform?: 'android' | 'ios', sessionId?: string, limit?: number, since?: string }) {
|
|
52
|
-
const effectivePlatform = platform || 'android'
|
|
53
|
-
const sid = sessionId || 'default'
|
|
54
|
-
if (effectivePlatform === 'android') {
|
|
55
|
-
return await new AndroidObserve().readLogStream(sid, limit ?? 100, since)
|
|
56
|
-
} else {
|
|
57
|
-
return await new iOSObserve().readLogStream(sid, limit ?? 100, since)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
static async stopLogStreamHandler({ platform, sessionId }: { platform?: 'android' | 'ios', sessionId?: string }) {
|
|
62
|
-
const effectivePlatform = platform || 'android'
|
|
63
|
-
const sid = sessionId || 'default'
|
|
64
|
-
if (effectivePlatform === 'android') {
|
|
65
|
-
return await new AndroidObserve().stopLogStream(sid)
|
|
66
|
-
} else {
|
|
67
|
-
return await new iOSObserve().stopLogStream(sid)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
static async captureScreenshotHandler({ platform, deviceId }: { platform?: 'android' | 'ios', deviceId?: string }) {
|
|
72
|
-
const effectivePlatform = platform || 'android'
|
|
73
|
-
if (effectivePlatform === 'android') {
|
|
74
|
-
const resolved = await resolveTargetDevice({ platform: 'android', deviceId })
|
|
75
|
-
return await new AndroidObserve().captureScreen(resolved.id)
|
|
76
|
-
} else {
|
|
77
|
-
const resolved = await resolveTargetDevice({ platform: 'ios', deviceId })
|
|
78
|
-
return await new iOSObserve().captureScreenshot(resolved.id)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
package/test/device/README.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
Device-dependent integration tests
|
|
2
|
-
|
|
3
|
-
Overview
|
|
4
|
-
|
|
5
|
-
This folder contains integration tests that require a simulator or a real device (Android/iOS). These tests exercise real device flows (install, start, UI-tree, logs, interaction) and are intentionally gated from the default CI to avoid failures on runners without devices.
|
|
6
|
-
|
|
7
|
-
Prerequisites
|
|
8
|
-
|
|
9
|
-
- Build the project: npm run build
|
|
10
|
-
- Android: adb available (set ADB_PATH if custom) and a connected device or emulator
|
|
11
|
-
- iOS: idb (fb-idb) and idb_companion installed and available. Prefer setting MCP_IDB_PATH or IDB_PATH, or add `idb` to PATH. For simulator tests ensure a simulator is booted.
|
|
12
|
-
|
|
13
|
-
Environment variables
|
|
14
|
-
|
|
15
|
-
- RUN_DEVICE_TESTS=true — enable device tests when running the integration runner
|
|
16
|
-
- ADB_PATH — custom path to adb (optional)
|
|
17
|
-
- MCP_IDB_PATH / IDB_PATH — path to idb CLI (optional)
|
|
18
|
-
- DEVICE_ID — when a test requires a device id
|
|
19
|
-
- APP_ID — when a test requires an app package/bundle id (used by some scripts)
|
|
20
|
-
|
|
21
|
-
How to run
|
|
22
|
-
|
|
23
|
-
- Run all non-device integration tests (default):
|
|
24
|
-
npm run test:integration
|
|
25
|
-
|
|
26
|
-
- Run device tests (all):
|
|
27
|
-
RUN_DEVICE_TESTS=true npm run test:integration
|
|
28
|
-
|
|
29
|
-
- Run a single device test (example: iOS UI tree):
|
|
30
|
-
npx tsx test/device/observe/test-ui-tree.ts ios booted
|
|
31
|
-
|
|
32
|
-
- Run install integration for a project:
|
|
33
|
-
npx tsx test/device/manage/install.integration.ts /path/to/project [deviceId]
|
|
34
|
-
|
|
35
|
-
iOS notes
|
|
36
|
-
|
|
37
|
-
- If using idb_companion, prefer starting it bound to a UDID to reduce flakiness:
|
|
38
|
-
idb_companion --udid <UDID> &
|
|
39
|
-
- Boot a simulator if needed:
|
|
40
|
-
xcrun simctl boot <UDID>
|
|
41
|
-
|
|
42
|
-
Android notes
|
|
43
|
-
|
|
44
|
-
- Ensure an emulator or device is connected (adb devices)
|
|
45
|
-
- Some tests read DEVICE_ID or accept it as an argument
|
|
46
|
-
|
|
47
|
-
CI recommendation
|
|
48
|
-
|
|
49
|
-
Keep these tests gated behind RUN_DEVICE_TESTS and run them only on macOS runners (for iOS) or self-hosted runners with attached devices.
|
package/test/device/index.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Device tests runner
|
|
3
|
-
// This runner loads minimal utilities, and only imports the device tests when
|
|
4
|
-
// RUN_DEVICE_TESTS=true to avoid running them in CI by default.
|
|
5
|
-
|
|
6
|
-
import './utils/test-dist';
|
|
7
|
-
|
|
8
|
-
(async () => {
|
|
9
|
-
if (process.env.RUN_DEVICE_TESTS === 'true') {
|
|
10
|
-
console.log('RUN_DEVICE_TESTS=true: running device integration tests');
|
|
11
|
-
await Promise.all([
|
|
12
|
-
import('./manage/install.integration'),
|
|
13
|
-
import('./manage/run-install-android'),
|
|
14
|
-
import('./manage/run-install-ios'),
|
|
15
|
-
import('./observe/logstream-real'),
|
|
16
|
-
import('./observe/test-ui-tree'),
|
|
17
|
-
import('./observe/wait_for_element_real'),
|
|
18
|
-
import('./interact/run-real-test'),
|
|
19
|
-
import('./interact/smoke-test')
|
|
20
|
-
]);
|
|
21
|
-
console.log('Device integration imports complete');
|
|
22
|
-
} else {
|
|
23
|
-
console.log('Skipping device-dependent integration tests. Set RUN_DEVICE_TESTS=true to enable them.');
|
|
24
|
-
}
|
|
25
|
-
})();
|
|
26
|
-
|
|
27
|
-
console.log('Device tests runner ready');
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises'
|
|
2
|
-
import { listAndroidDevices } from '../../../dist/android/utils.js'
|
|
3
|
-
import { getAndroidLogs, captureAndroidScreen } from '../../../dist/android.js'
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
try {
|
|
7
|
-
console.log('Listing Android devices...')
|
|
8
|
-
const devices = await listAndroidDevices()
|
|
9
|
-
console.log('Devices:', JSON.stringify(devices, null, 2))
|
|
10
|
-
|
|
11
|
-
if (devices.length === 0) {
|
|
12
|
-
console.log('No Android devices found; aborting Android smoke test.')
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const target = devices[0]
|
|
17
|
-
console.log('Using target device:', target.id)
|
|
18
|
-
|
|
19
|
-
console.log('Fetching logs (last 50 lines)...')
|
|
20
|
-
const logsRes = await getAndroidLogs(undefined, 50, target.id)
|
|
21
|
-
console.log(`Retrieved ${logsRes.logCount} log lines`)
|
|
22
|
-
if (logsRes.logs && logsRes.logs.length > 0) {
|
|
23
|
-
console.log('Sample log:', logsRes.logs[Math.max(0, logsRes.logs.length - 1)].substring(0, 200))
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log('Capturing screenshot...')
|
|
27
|
-
const shot = await captureAndroidScreen(target.id)
|
|
28
|
-
if (shot && shot.screenshot) {
|
|
29
|
-
const file = `smoke-test-android-${target.id}.png`
|
|
30
|
-
await fs.writeFile(file, Buffer.from(shot.screenshot, 'base64'))
|
|
31
|
-
console.log('Screenshot saved to', file)
|
|
32
|
-
} else {
|
|
33
|
-
console.log('No screenshot returned')
|
|
34
|
-
}
|
|
35
|
-
} catch {
|
|
36
|
-
console.error('Smoke test script failed:', err)
|
|
37
|
-
process.exit(1)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
main()
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import assert from 'assert'
|
|
2
|
-
import { detectJavaHome } from '../../../src/utils/java.js'
|
|
3
|
-
|
|
4
|
-
// These tests are lightweight smoke tests; they don't rely on actual JDK17 installs,
|
|
5
|
-
// but exercise the failure modes and ensure the function returns undefined or a string.
|
|
6
|
-
|
|
7
|
-
export async function run() {
|
|
8
|
-
const res = await detectJavaHome()
|
|
9
|
-
// It's acceptable for local dev env to not have JDK17; just ensure call returns (string|undefined)
|
|
10
|
-
assert.ok(typeof res === 'string' || typeof res === 'undefined')
|
|
11
|
-
|
|
12
|
-
// Basic mocking: set JAVA_HOME to a fake path and ensure detectJavaHome still runs without throwing.
|
|
13
|
-
const orig = process.env.JAVA_HOME
|
|
14
|
-
process.env.JAVA_HOME = '/non/existent/java/home'
|
|
15
|
-
await detectJavaHome()
|
|
16
|
-
// accept either undefined or string results depending on environment; do not fail deterministically
|
|
17
|
-
process.env.JAVA_HOME = orig
|
|
18
|
-
|
|
19
|
-
console.log('detectJavaHome tests passed')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
run().catch((e) => { console.error(e); process.exit(1) })
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|