mobile-debug-mcp 0.24.8 → 0.25.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.
@@ -0,0 +1,43 @@
1
+ import assert from 'assert'
2
+ import { traverseNode } from '../../../src/utils/android/utils.js'
3
+ import { traverseIDBNode } from '../../../src/observe/ios.js'
4
+
5
+ async function run() {
6
+ const androidElements: any[] = []
7
+ traverseNode({
8
+ '@_class': 'android.widget.SeekBar',
9
+ '@_text': '',
10
+ '@_content-desc': 'Duration',
11
+ '@_clickable': 'true',
12
+ '@_enabled': 'true',
13
+ '@_selected': 'true',
14
+ '@_progress': '7',
15
+ '@_max': '14',
16
+ '@_bounds': '[0,0][200,40]'
17
+ }, androidElements)
18
+
19
+ assert.strictEqual(androidElements.length, 1)
20
+ assert.deepStrictEqual(androidElements[0].state?.selected, 'Duration')
21
+ assert.strictEqual(androidElements[0].state?.raw_value, 7)
22
+ assert.strictEqual(androidElements[0].state?.value, 50)
23
+ assert.deepStrictEqual(androidElements[0].state?.value_range, { min: 0, max: 14 })
24
+
25
+ const iosElements: any[] = []
26
+ traverseIDBNode({
27
+ AXElementType: 'Slider',
28
+ AXLabel: 'Playback speed',
29
+ AXValue: '0.75',
30
+ AXTraits: ['UIAccessibilityTraitAdjustable']
31
+ }, iosElements)
32
+
33
+ assert.strictEqual(iosElements.length, 1)
34
+ assert.strictEqual(iosElements[0].state?.value, 75)
35
+ assert.strictEqual(iosElements[0].state?.raw_value, 0.75)
36
+
37
+ console.log('state extraction tests passed')
38
+ }
39
+
40
+ run().catch((error) => {
41
+ console.error(error)
42
+ process.exit(1)
43
+ })
@@ -12,6 +12,7 @@ async function run() {
12
12
  const originalTapHandler = (ToolsInteract as any).tapHandler
13
13
  const originalExpectScreenHandler = (ToolsInteract as any).expectScreenHandler
14
14
  const originalExpectElementVisibleHandler = (ToolsInteract as any).expectElementVisibleHandler
15
+ const originalExpectStateHandler = (ToolsInteract as any).expectStateHandler
15
16
  const originalStartApp = AndroidManage.prototype.startApp
16
17
  const originalCaptureScreenshotHandler = (ToolsObserve as any).captureScreenshotHandler
17
18
  const originalGetUITreeHandler = (ToolsObserve as any).getUITreeHandler
@@ -130,8 +131,8 @@ async function run() {
130
131
  selector: { text: 'Ready' },
131
132
  element_id: 'el_ready',
132
133
  expected_condition: 'visible',
133
- element: { elementId: 'el_ready', text: 'Ready', resource_id: null, accessibility_id: null, class: 'TextView', bounds: [0, 0, 10, 10], index: 0 },
134
- observed: { status: 'success', matched_count: 1, condition_satisfied: true, selected_index: 0, last_matched_element: { elementId: 'el_ready', text: 'Ready', resource_id: null, accessibility_id: null, class: 'TextView', bounds: [0, 0, 10, 10], index: 0 } },
134
+ element: { elementId: 'el_ready', text: 'Ready', resource_id: null, accessibility_id: null, class: 'TextView', bounds: [0, 0, 10, 10], index: 0, state: { enabled: true } },
135
+ observed: { status: 'success', matched_count: 1, condition_satisfied: true, selected_index: 0, last_matched_element: { elementId: 'el_ready', text: 'Ready', resource_id: null, accessibility_id: null, class: 'TextView', bounds: [0, 0, 10, 10], index: 0, state: { enabled: true } } },
135
136
  reason: 'selector is visible'
136
137
  })
137
138
 
@@ -141,6 +142,42 @@ async function run() {
141
142
  assert.strictEqual(expectElementPayload.element_id, 'el_ready')
142
143
  assert.strictEqual(expectElementPayload.expected_condition, 'visible')
143
144
 
145
+ ;(ToolsObserve as any).getUITreeHandler = async () => ({
146
+ device: { platform: 'android', id: 'mock', osVersion: '14', model: 'Pixel', simulator: true },
147
+ resolution: { width: 1080, height: 2400 },
148
+ elements: [{
149
+ text: 'Notifications',
150
+ depth: 0,
151
+ center: { x: 50, y: 20 },
152
+ state: { checked: true, selected: 'Notifications' }
153
+ }]
154
+ })
155
+
156
+ ;(ToolsInteract as any).expectStateHandler = async () => ({
157
+ success: true,
158
+ selector: { text: 'Notifications' },
159
+ element_id: 'el_notifications',
160
+ expected_state: { property: 'checked', expected: true },
161
+ element: {
162
+ elementId: 'el_notifications',
163
+ text: 'Notifications',
164
+ resource_id: null,
165
+ accessibility_id: null,
166
+ class: 'Switch',
167
+ bounds: [0, 0, 10, 10],
168
+ index: 0,
169
+ state: { checked: true, selected: 'Notifications' }
170
+ },
171
+ observed_state: { property: 'checked', value: true, raw_value: true },
172
+ reason: 'checked matches expected value'
173
+ })
174
+
175
+ const expectStateResponse = await handleToolCall('expect_state', { selector: { text: 'Notifications' }, property: 'checked', expected: true })
176
+ const expectStatePayload = JSON.parse((expectStateResponse as any).content[0].text)
177
+ assert.strictEqual(expectStatePayload.success, true)
178
+ assert.strictEqual(expectStatePayload.expected_state.property, 'checked')
179
+ assert.strictEqual(expectStatePayload.observed_state.value, true)
180
+
144
181
  ;(ToolsInteract as any).tapHandler = async () => {
145
182
  throw new Error('boom')
146
183
  }
@@ -234,6 +271,7 @@ async function run() {
234
271
  ;(ToolsInteract as any).tapHandler = originalTapHandler
235
272
  ;(ToolsInteract as any).expectScreenHandler = originalExpectScreenHandler
236
273
  ;(ToolsInteract as any).expectElementVisibleHandler = originalExpectElementVisibleHandler
274
+ ;(ToolsInteract as any).expectStateHandler = originalExpectStateHandler
237
275
  AndroidManage.prototype.startApp = originalStartApp
238
276
  ;(ToolsObserve as any).captureScreenshotHandler = originalCaptureScreenshotHandler
239
277
  ;(ToolsObserve as any).getUITreeHandler = originalGetUITreeHandler