mobile-debug-mcp 0.29.0 → 0.30.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.
@@ -2,74 +2,127 @@ import assert from 'assert'
2
2
  import { ToolsInteract } from '../../../src/interact/index.js'
3
3
  import { ToolsObserve } from '../../../src/observe/index.js'
4
4
 
5
- async function run() {
5
+ type UiTree = {
6
+ device: { platform: 'android', id: string, osVersion: string, model: string, simulator: boolean }
7
+ screen: string
8
+ resolution: { width: number, height: number }
9
+ elements: Array<{ text: string, type: string, bounds: number[], visible: boolean }>
10
+ snapshot_revision: number
11
+ captured_at_ms: number
12
+ }
13
+
14
+ function makeTree(screen: string, revision: number): UiTree {
15
+ return {
16
+ device: { platform: 'android', id: 'mock', osVersion: '14', model: 'Pixel', simulator: true },
17
+ screen,
18
+ resolution: { width: 1080, height: 2400 },
19
+ elements: [{ text: screen, type: 'TextView', bounds: [0, 0, 100, 40], visible: true }],
20
+ snapshot_revision: revision,
21
+ captured_at_ms: 1000 + revision
22
+ }
23
+ }
24
+
25
+ async function runScenario({
26
+ snapshots,
27
+ expectedChange,
28
+ timeoutMs,
29
+ stabilityWindowMs,
30
+ stepMs
31
+ }: {
32
+ snapshots: UiTree[]
33
+ expectedChange: 'hierarchy_diff' | 'text_change' | 'state_change'
34
+ timeoutMs: number
35
+ stabilityWindowMs?: number
36
+ stepMs: number
37
+ }) {
6
38
  const originalGetUITreeHandler = (ToolsObserve as any).getUITreeHandler
39
+ const originalSetTimeout = globalThis.setTimeout
40
+ const originalDateNow = Date.now
41
+ let now = 0
42
+ let calls = 0
43
+ const delays: number[] = []
7
44
 
8
45
  try {
9
- let calls = 0
46
+ ;(Date as any).now = () => now
47
+ ;(globalThis as any).setTimeout = (callback: (...args: any[]) => void, delay?: number) => {
48
+ delays.push(typeof delay === 'number' ? delay : 0)
49
+ now += stepMs
50
+ callback()
51
+ return 0
52
+ }
53
+
10
54
  ;(ToolsObserve as any).getUITreeHandler = async () => {
11
55
  calls++
12
- if (calls === 1) {
13
- return {
14
- device: { platform: 'android', id: 'mock', osVersion: '14', model: 'Pixel', simulator: true },
15
- screen: 'Loading',
16
- resolution: { width: 1080, height: 2400 },
17
- elements: [{ text: 'Loading', type: 'TextView', bounds: [0, 0, 100, 40], visible: true }],
18
- snapshot_revision: 1,
19
- captured_at_ms: 1000
20
- }
21
- }
22
-
23
- return {
24
- device: { platform: 'android', id: 'mock', osVersion: '14', model: 'Pixel', simulator: true },
25
- screen: 'Loaded',
26
- resolution: { width: 1080, height: 2400 },
27
- elements: [{ text: 'Loaded', type: 'TextView', bounds: [0, 0, 100, 40], visible: true }],
28
- snapshot_revision: 2,
29
- captured_at_ms: 2000
30
- }
56
+ return snapshots[Math.min(calls - 1, snapshots.length - 1)]
31
57
  }
32
58
 
33
- const success = await ToolsInteract.waitForUIChangeHandler({
34
- platform: 'android',
35
- deviceId: 'mock',
36
- expected_change: 'text_change',
37
- timeout_ms: 1500,
38
- stability_window_ms: 1
39
- })
40
-
41
- assert.strictEqual(success.success, true)
42
- assert.strictEqual(success.observed_change, 'text_change')
43
- assert.strictEqual(success.snapshot_revision, 2)
44
- assert.strictEqual(success.timeout, false)
45
-
46
- ;(ToolsObserve as any).getUITreeHandler = async () => ({
47
- device: { platform: 'android', id: 'mock', osVersion: '14', model: 'Pixel', simulator: true },
48
- screen: 'Static',
49
- resolution: { width: 1080, height: 2400 },
50
- elements: [{ text: 'Static', type: 'TextView', bounds: [0, 0, 100, 40], visible: true }],
51
- snapshot_revision: 9,
52
- captured_at_ms: 3000
53
- })
54
-
55
- const timeout = await ToolsInteract.waitForUIChangeHandler({
59
+ const result = await ToolsInteract.waitForUIChangeHandler({
56
60
  platform: 'android',
57
61
  deviceId: 'mock',
58
- expected_change: 'state_change',
59
- timeout_ms: 700,
60
- stability_window_ms: 1
62
+ expected_change: expectedChange,
63
+ timeout_ms: timeoutMs,
64
+ stability_window_ms: stabilityWindowMs
61
65
  })
62
66
 
63
- assert.strictEqual(timeout.success, false)
64
- assert.strictEqual(timeout.observed_change, null)
65
- assert.strictEqual(timeout.timeout, true)
66
-
67
- console.log('wait_for_ui_change tests passed')
67
+ return { result, calls, delays }
68
68
  } finally {
69
69
  ;(ToolsObserve as any).getUITreeHandler = originalGetUITreeHandler
70
+ ;(globalThis as any).setTimeout = originalSetTimeout
71
+ ;(Date as any).now = originalDateNow
70
72
  }
71
73
  }
72
74
 
75
+ async function run() {
76
+ const success = await runScenario({
77
+ snapshots: [makeTree('Loading', 1), makeTree('Loaded', 2)],
78
+ expectedChange: 'text_change',
79
+ timeoutMs: 1500,
80
+ stabilityWindowMs: 1,
81
+ stepMs: 1
82
+ })
83
+
84
+ assert.strictEqual(success.result.success, true)
85
+ assert.strictEqual(success.result.observed_change, 'text_change')
86
+ assert.strictEqual(success.result.snapshot_revision, 2)
87
+ assert.strictEqual(success.result.timeout, false)
88
+
89
+ const timeout = await runScenario({
90
+ snapshots: [makeTree('Static', 9)],
91
+ expectedChange: 'state_change',
92
+ timeoutMs: 5,
93
+ stabilityWindowMs: 1,
94
+ stepMs: 1
95
+ })
96
+
97
+ assert.strictEqual(timeout.result.success, false)
98
+ assert.strictEqual(timeout.result.observed_change, null)
99
+ assert.strictEqual(timeout.result.timeout, true)
100
+
101
+ const defaultWindow = await runScenario({
102
+ snapshots: [makeTree('Loading', 1), makeTree('Loaded', 2), makeTree('Loaded', 3), makeTree('Loaded', 4)],
103
+ expectedChange: 'text_change',
104
+ timeoutMs: 2000,
105
+ stepMs: 260
106
+ })
107
+
108
+ assert.strictEqual(defaultWindow.result.success, true)
109
+ assert.strictEqual(defaultWindow.calls, 4)
110
+ assert.deepStrictEqual(defaultWindow.delays, [300, 300, 300])
111
+
112
+ const resetWindow = await runScenario({
113
+ snapshots: [makeTree('Loading', 1), makeTree('Loaded', 2), makeTree('Loaded-again', 3), makeTree('Loaded-again', 4), makeTree('Loaded-again', 5)],
114
+ expectedChange: 'text_change',
115
+ timeoutMs: 2000,
116
+ stabilityWindowMs: 300,
117
+ stepMs: 150
118
+ })
119
+
120
+ assert.strictEqual(resetWindow.result.success, true)
121
+ assert.strictEqual(resetWindow.calls, 5)
122
+
123
+ console.log('wait_for_ui_change tests passed')
124
+ }
125
+
73
126
  run().catch((error) => {
74
127
  console.error(error)
75
128
  process.exit(1)