appium-mcp 1.3.0 → 1.5.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/CHANGELOG.md +12 -0
- package/README.md +2 -0
- package/dist/tools/app-management/install-app.js +1 -1
- package/dist/tools/app-management/install-app.js.map +1 -1
- package/dist/tools/app-management/terminate-app.js +1 -1
- package/dist/tools/app-management/terminate-app.js.map +1 -1
- package/dist/tools/app-management/uninstall-app.js +1 -1
- package/dist/tools/app-management/uninstall-app.js.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/interactions/drag-and-drop.d.ts +2 -0
- package/dist/tools/interactions/drag-and-drop.js +173 -0
- package/dist/tools/interactions/drag-and-drop.js.map +1 -0
- package/dist/tools/interactions/long-press.d.ts +2 -0
- package/dist/tools/interactions/long-press.js +101 -0
- package/dist/tools/interactions/long-press.js.map +1 -0
- package/package.json +1 -1
- package/src/tools/README.md +2 -0
- package/src/tools/app-management/install-app.ts +1 -1
- package/src/tools/app-management/terminate-app.ts +1 -1
- package/src/tools/app-management/uninstall-app.ts +1 -1
- package/src/tools/index.ts +4 -0
- package/src/tools/interactions/drag-and-drop.ts +229 -0
- package/src/tools/interactions/long-press.ts +108 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.5.0](https://github.com/appium/appium-mcp/compare/v1.4.0...v1.5.0) (2025-12-19)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **interactions:** add drag and drop tool for element and coordinate-based drag operations ([#55](https://github.com/appium/appium-mcp/issues/55)) ([571942e](https://github.com/appium/appium-mcp/commit/571942ecbd2d7ef395cc8e6a8aaf158dcf0f54fb))
|
|
6
|
+
|
|
7
|
+
## [1.4.0](https://github.com/appium/appium-mcp/compare/v1.3.0...v1.4.0) (2025-12-07)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **interactions:** add long press tool for press and hold gestures ([#53](https://github.com/appium/appium-mcp/issues/53)) ([ef6092e](https://github.com/appium/appium-mcp/commit/ef6092e0e100dd0535f1d6bf371ad794969e863d))
|
|
12
|
+
|
|
1
13
|
## [1.3.0](https://github.com/appium/appium-mcp/compare/v1.2.0...v1.3.0) (2025-12-05)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/README.md
CHANGED
|
@@ -192,6 +192,8 @@ MCP Appium provides a comprehensive set of tools organized into the following ca
|
|
|
192
192
|
| `appium_find_element` | Find a specific element using various locator strategies (xpath, id, accessibility id, etc.) |
|
|
193
193
|
| `appium_click` | Click on an element |
|
|
194
194
|
| `appium_double_tap` | Perform double tap on an element |
|
|
195
|
+
| `appium_long_press` | Perform a long press (press and hold) gesture on an element |
|
|
196
|
+
| `appium_drag_and_drop` | Perform a drag and drop gesture from a source location to a target location (supports element-to-element, element-to-coordinates, coordinates-to-element, and coordinates-to-coordinates) |
|
|
195
197
|
| `appium_set_value` | Enter text into an input field |
|
|
196
198
|
| `appium_get_text` | Get text content from an element |
|
|
197
199
|
|
|
@@ -5,7 +5,7 @@ export default function installApp(server) {
|
|
|
5
5
|
path: z.string().describe('Path to the app file to install'),
|
|
6
6
|
});
|
|
7
7
|
server.addTool({
|
|
8
|
-
name: '
|
|
8
|
+
name: 'appium_install_app',
|
|
9
9
|
description: 'Install an app on the device from a file path.',
|
|
10
10
|
parameters: schema,
|
|
11
11
|
execute: async (args) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/install-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,MAAe;IAChD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KAC7D,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"install-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/install-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,MAAe;IAChD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KAC7D,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,gDAAgD;QAC7D,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE,KAAK,EAAE,IAA4B,EAAE,EAAE;YAC9C,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACrC,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBACzC,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;gBAC7D,MAAO,MAAc,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;gBAC5D,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,4BAA4B;yBACnC;qBACF;iBACF,CAAC;YACJ,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,+BAA+B,GAAG,CAAC,QAAQ,EAAE,EAAE;yBACtD;qBACF;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -7,7 +7,7 @@ export default function terminateApp(server) {
|
|
|
7
7
|
.describe('App identifier (package name for Android, bundle ID for iOS)'),
|
|
8
8
|
});
|
|
9
9
|
server.addTool({
|
|
10
|
-
name: '
|
|
10
|
+
name: 'appium_terminate_app',
|
|
11
11
|
description: 'Terminate an app on the device.',
|
|
12
12
|
parameters: schema,
|
|
13
13
|
execute: async (args) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminate-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/terminate-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAe;IAClD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,8DAA8D,CAAC;KAC5E,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"terminate-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/terminate-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAe;IAClD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,8DAA8D,CAAC;KAC5E,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,iCAAiC;QAC9C,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE,KAAK,EAAE,IAA4B,EAAE,EAAE;YAC9C,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACrC,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBACzC,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;gBAC5D,MAAO,MAAc,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;gBAC9D,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,6BAA6B;yBACpC;qBACF;iBACF,CAAC;YACJ,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,iCAAiC,GAAG,CAAC,QAAQ,EAAE,EAAE;yBACxD;qBACF;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -7,7 +7,7 @@ export default function uninstallApp(server) {
|
|
|
7
7
|
.describe('App identifier (package name for Android, bundle ID for iOS)'),
|
|
8
8
|
});
|
|
9
9
|
server.addTool({
|
|
10
|
-
name: '
|
|
10
|
+
name: 'appium_uninstall_app',
|
|
11
11
|
description: 'Uninstall an app from the device.',
|
|
12
12
|
parameters: schema,
|
|
13
13
|
execute: async (args) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/uninstall-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAe;IAClD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,8DAA8D,CAAC;KAC5E,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"uninstall-app.js","sourceRoot":"","sources":["../../../src/tools/app-management/uninstall-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAe;IAClD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,8DAA8D,CAAC;KAC5E,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC;QACb,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,mCAAmC;QAChD,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE,KAAK,EAAE,IAA4B,EAAE,EAAE;YAC9C,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACrC,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBACzC,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;gBAC5D,MAAO,MAAc,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;gBAC3D,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,8BAA8B;yBACrC;qBACF;iBACF,CAAC;YACJ,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,iCAAiC,GAAG,CAAC,QAAQ,EAAE,EAAE;yBACxD;qBACF;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/dist/tools/index.js
CHANGED
|
@@ -15,6 +15,8 @@ import swipe from './navigations/swipe.js';
|
|
|
15
15
|
import findElement from './interactions/find.js';
|
|
16
16
|
import clickElement from './interactions/click.js';
|
|
17
17
|
import doubleTap from './interactions/double-tap.js';
|
|
18
|
+
import longPress from './interactions/long-press.js';
|
|
19
|
+
import dragAndDrop from './interactions/drag-and-drop.js';
|
|
18
20
|
import setValue from './interactions/set-value.js';
|
|
19
21
|
import getText from './interactions/get-text.js';
|
|
20
22
|
import getPageSource from './interactions/get-page-source.js';
|
|
@@ -105,6 +107,8 @@ export default function registerTools(server) {
|
|
|
105
107
|
findElement(server);
|
|
106
108
|
clickElement(server);
|
|
107
109
|
doubleTap(server);
|
|
110
|
+
longPress(server);
|
|
111
|
+
dragAndDrop(server);
|
|
108
112
|
setValue(server);
|
|
109
113
|
getText(server);
|
|
110
114
|
getPageSource(server);
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getDriver, getPlatformName } from '../../session-store.js';
|
|
3
|
+
import { elementUUIDScheme } from '../../schema.js';
|
|
4
|
+
const DROP_PAUSE_DURATION_MS = 150;
|
|
5
|
+
async function performDragAndDrop(driver, startX, startY, endX, endY, duration, longPressDuration) {
|
|
6
|
+
await driver.performActions([
|
|
7
|
+
{
|
|
8
|
+
type: 'pointer',
|
|
9
|
+
id: 'finger1',
|
|
10
|
+
parameters: { pointerType: 'touch' },
|
|
11
|
+
actions: [
|
|
12
|
+
{ type: 'pointerMove', duration: 0, x: startX, y: startY },
|
|
13
|
+
{ type: 'pointerDown', button: 0 },
|
|
14
|
+
{ type: 'pause', duration: longPressDuration },
|
|
15
|
+
{ type: 'pointerMove', duration: duration, x: endX, y: endY },
|
|
16
|
+
{ type: 'pause', duration: DROP_PAUSE_DURATION_MS },
|
|
17
|
+
{ type: 'pointerUp', button: 0 },
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
22
|
+
export default function dragAndDrop(server) {
|
|
23
|
+
const dragAndDropSchema = z.object({
|
|
24
|
+
sourceElementUUID: elementUUIDScheme
|
|
25
|
+
.trim()
|
|
26
|
+
.min(1)
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('UUID of the source element to drag from. Either sourceElementUUID or sourceX/sourceY must be provided.'),
|
|
29
|
+
sourceX: z
|
|
30
|
+
.number()
|
|
31
|
+
.int()
|
|
32
|
+
.min(0)
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Starting X coordinate. Required if sourceElementUUID is not provided.'),
|
|
35
|
+
sourceY: z
|
|
36
|
+
.number()
|
|
37
|
+
.int()
|
|
38
|
+
.min(0)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe('Starting Y coordinate. Required if sourceElementUUID is not provided.'),
|
|
41
|
+
targetElementUUID: elementUUIDScheme
|
|
42
|
+
.trim()
|
|
43
|
+
.min(1)
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('UUID of the target element to drop on. Either targetElementUUID or targetX/targetY must be provided.'),
|
|
46
|
+
targetX: z
|
|
47
|
+
.number()
|
|
48
|
+
.int()
|
|
49
|
+
.min(0)
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Ending X coordinate. Required if targetElementUUID is not provided.'),
|
|
52
|
+
targetY: z
|
|
53
|
+
.number()
|
|
54
|
+
.int()
|
|
55
|
+
.min(0)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('Ending Y coordinate. Required if targetElementUUID is not provided.'),
|
|
58
|
+
duration: z
|
|
59
|
+
.number()
|
|
60
|
+
.int()
|
|
61
|
+
.min(100)
|
|
62
|
+
.max(5000)
|
|
63
|
+
.default(1200)
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('Duration of the drag movement in milliseconds. Default is 1200ms.'),
|
|
66
|
+
longPressDuration: z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.min(400)
|
|
70
|
+
.max(2000)
|
|
71
|
+
.default(600)
|
|
72
|
+
.optional()
|
|
73
|
+
.describe('Duration of the long press before dragging in milliseconds. Default is 600ms.'),
|
|
74
|
+
});
|
|
75
|
+
server.addTool({
|
|
76
|
+
name: 'appium_drag_and_drop',
|
|
77
|
+
description: `Perform a drag and drop gesture from a source location to a target location.
|
|
78
|
+
The gesture includes:
|
|
79
|
+
1. Long press (default 600ms, configurable) on the source to initiate drag mode
|
|
80
|
+
2. While holding, drag to the target location
|
|
81
|
+
3. Release at the target to complete the drop
|
|
82
|
+
|
|
83
|
+
Supports four modes:
|
|
84
|
+
1. Element to Element: Drag from one element to another element
|
|
85
|
+
2. Element to Coordinates: Drag from an element to specific coordinates
|
|
86
|
+
3. Coordinates to Element: Drag from coordinates to an element
|
|
87
|
+
4. Coordinates to Coordinates: Drag from coordinates to coordinates
|
|
88
|
+
|
|
89
|
+
This is useful for reordering lists, moving items, drag-to-delete, and other drag interactions.`,
|
|
90
|
+
parameters: dragAndDropSchema,
|
|
91
|
+
annotations: {
|
|
92
|
+
readOnlyHint: false,
|
|
93
|
+
openWorldHint: false,
|
|
94
|
+
},
|
|
95
|
+
execute: async (args, context) => {
|
|
96
|
+
const driver = getDriver();
|
|
97
|
+
if (!driver) {
|
|
98
|
+
throw new Error('No driver found');
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const platform = getPlatformName(driver);
|
|
102
|
+
const duration = args.duration || 1200;
|
|
103
|
+
const longPressDuration = args.longPressDuration || 600;
|
|
104
|
+
if (!args.sourceElementUUID &&
|
|
105
|
+
(args.sourceX === undefined || args.sourceY === undefined)) {
|
|
106
|
+
throw new Error('Either sourceElementUUID or both sourceX and sourceY must be provided.');
|
|
107
|
+
}
|
|
108
|
+
if (!args.targetElementUUID &&
|
|
109
|
+
(args.targetX === undefined || args.targetY === undefined)) {
|
|
110
|
+
throw new Error('Either targetElementUUID or both targetX and targetY must be provided.');
|
|
111
|
+
}
|
|
112
|
+
let startX, startY;
|
|
113
|
+
let endX, endY;
|
|
114
|
+
if (args.sourceElementUUID) {
|
|
115
|
+
const rect = await driver.getElementRect(args.sourceElementUUID);
|
|
116
|
+
startX = Math.floor(rect.x + rect.width / 2);
|
|
117
|
+
startY = Math.floor(rect.y + rect.height / 2);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
startX = args.sourceX;
|
|
121
|
+
startY = args.sourceY;
|
|
122
|
+
}
|
|
123
|
+
if (args.targetElementUUID) {
|
|
124
|
+
const rect = await driver.getElementRect(args.targetElementUUID);
|
|
125
|
+
endX = Math.floor(rect.x + rect.width / 2);
|
|
126
|
+
endY = Math.floor(rect.y + rect.height / 2);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
endX = args.targetX;
|
|
130
|
+
endY = args.targetY;
|
|
131
|
+
}
|
|
132
|
+
const { width, height } = await driver.getWindowSize();
|
|
133
|
+
if (startX < 0 || startX >= width || startY < 0 || startY >= height) {
|
|
134
|
+
throw new Error(`Source coordinates (${startX}, ${startY}) are out of screen bounds (${width}x${height})`);
|
|
135
|
+
}
|
|
136
|
+
if (endX < 0 || endX >= width || endY < 0 || endY >= height) {
|
|
137
|
+
throw new Error(`Target coordinates (${endX}, ${endY}) are out of screen bounds (${width}x${height})`);
|
|
138
|
+
}
|
|
139
|
+
if (platform === 'Android' || platform === 'iOS') {
|
|
140
|
+
await performDragAndDrop(driver, startX, startY, endX, endY, duration, longPressDuration);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
throw new Error(`Unsupported platform: ${platform}. Only Android and iOS are supported.`);
|
|
144
|
+
}
|
|
145
|
+
const sourceDesc = args.sourceElementUUID
|
|
146
|
+
? `element ${args.sourceElementUUID}`
|
|
147
|
+
: `coordinates (${startX}, ${startY})`;
|
|
148
|
+
const targetDesc = args.targetElementUUID
|
|
149
|
+
? `element ${args.targetElementUUID}`
|
|
150
|
+
: `coordinates (${endX}, ${endY})`;
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: `Successfully performed drag and drop from ${sourceDesc} to ${targetDesc}.`,
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
return {
|
|
162
|
+
content: [
|
|
163
|
+
{
|
|
164
|
+
type: 'text',
|
|
165
|
+
text: `Failed to perform drag and drop. Error: ${err.toString()}`,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=drag-and-drop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-and-drop.js","sourceRoot":"","sources":["../../../src/tools/interactions/drag-and-drop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getDriver, getPlatformName } from '../../session-store.js';
|
|
3
|
+
import { elementUUIDScheme } from '../../schema.js';
|
|
4
|
+
export default function longPress(server) {
|
|
5
|
+
const longPressSchema = z.object({
|
|
6
|
+
elementUUID: elementUUIDScheme,
|
|
7
|
+
duration: z
|
|
8
|
+
.number()
|
|
9
|
+
.int()
|
|
10
|
+
.min(500)
|
|
11
|
+
.max(10000)
|
|
12
|
+
.default(2000)
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Duration of the long press in milliseconds. Default is 2000ms.'),
|
|
15
|
+
});
|
|
16
|
+
server.addTool({
|
|
17
|
+
name: 'appium_long_press',
|
|
18
|
+
description: 'Perform a long press (press and hold) gesture on an element',
|
|
19
|
+
parameters: longPressSchema,
|
|
20
|
+
annotations: {
|
|
21
|
+
readOnlyHint: false,
|
|
22
|
+
openWorldHint: false,
|
|
23
|
+
},
|
|
24
|
+
execute: async (args, context) => {
|
|
25
|
+
const driver = getDriver();
|
|
26
|
+
if (!driver) {
|
|
27
|
+
throw new Error('No driver found');
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const platform = getPlatformName(driver);
|
|
31
|
+
const duration = args.duration || 2000;
|
|
32
|
+
if (platform === 'Android') {
|
|
33
|
+
const rect = await driver.getElementRect(args.elementUUID);
|
|
34
|
+
const x = Math.floor(rect.x + rect.width / 2);
|
|
35
|
+
const y = Math.floor(rect.y + rect.height / 2);
|
|
36
|
+
await driver.performActions([
|
|
37
|
+
{
|
|
38
|
+
type: 'pointer',
|
|
39
|
+
id: 'finger1',
|
|
40
|
+
parameters: { pointerType: 'touch' },
|
|
41
|
+
actions: [
|
|
42
|
+
{ type: 'pointerMove', duration: 0, x, y },
|
|
43
|
+
{ type: 'pointerDown', button: 0 },
|
|
44
|
+
{ type: 'pause', duration: duration },
|
|
45
|
+
{ type: 'pointerUp', button: 0 },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
else if (platform === 'iOS') {
|
|
51
|
+
try {
|
|
52
|
+
await driver.execute('mobile: touchAndHold', {
|
|
53
|
+
elementId: args.elementUUID,
|
|
54
|
+
duration: duration / 1000,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (touchAndHoldError) {
|
|
58
|
+
const rect = await driver.getElementRect(args.elementUUID);
|
|
59
|
+
const x = Math.floor(rect.x + rect.width / 2);
|
|
60
|
+
const y = Math.floor(rect.y + rect.height / 2);
|
|
61
|
+
await driver.performActions([
|
|
62
|
+
{
|
|
63
|
+
type: 'pointer',
|
|
64
|
+
id: 'finger1',
|
|
65
|
+
parameters: { pointerType: 'touch' },
|
|
66
|
+
actions: [
|
|
67
|
+
{ type: 'pointerMove', duration: 0, x, y },
|
|
68
|
+
{ type: 'pointerDown', button: 0 },
|
|
69
|
+
{ type: 'pause', duration: duration },
|
|
70
|
+
{ type: 'pointerUp', button: 0 },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
throw new Error(`Unsupported platform: ${platform}. Only Android and iOS are supported.`);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: `Successfully performed long press on element ${args.elementUUID}`,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return {
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: `Failed to perform long press on element ${args.elementUUID}. err: ${err.toString()}`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=long-press.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"long-press.js","sourceRoot":"","sources":["../../../src/tools/interactions/long-press.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/tools/README.md
CHANGED
|
@@ -28,6 +28,8 @@ This directory contains all MCP tools available in MCP Appium.
|
|
|
28
28
|
- `find.ts` - Find elements
|
|
29
29
|
- `click.ts` - Click elements
|
|
30
30
|
- `double-tap.ts` - Double tap elements
|
|
31
|
+
- `long-press.ts` - Long press (press and hold) elements
|
|
32
|
+
- `drag-and-drop.ts` - Drag and drop elements or coordinates
|
|
31
33
|
- `set-value.ts` - Enter text
|
|
32
34
|
- `get-text.ts` - Get element text
|
|
33
35
|
- `get-page-source.ts` - Get page source (XML) from current screen
|
|
@@ -8,7 +8,7 @@ export default function installApp(server: FastMCP): void {
|
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
server.addTool({
|
|
11
|
-
name: '
|
|
11
|
+
name: 'appium_install_app',
|
|
12
12
|
description: 'Install an app on the device from a file path.',
|
|
13
13
|
parameters: schema,
|
|
14
14
|
execute: async (args: z.infer<typeof schema>) => {
|
|
@@ -10,7 +10,7 @@ export default function terminateApp(server: FastMCP): void {
|
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
server.addTool({
|
|
13
|
-
name: '
|
|
13
|
+
name: 'appium_terminate_app',
|
|
14
14
|
description: 'Terminate an app on the device.',
|
|
15
15
|
parameters: schema,
|
|
16
16
|
execute: async (args: z.infer<typeof schema>) => {
|
|
@@ -10,7 +10,7 @@ export default function uninstallApp(server: FastMCP): void {
|
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
server.addTool({
|
|
13
|
-
name: '
|
|
13
|
+
name: 'appium_uninstall_app',
|
|
14
14
|
description: 'Uninstall an app from the device.',
|
|
15
15
|
parameters: schema,
|
|
16
16
|
execute: async (args: z.infer<typeof schema>) => {
|
package/src/tools/index.ts
CHANGED
|
@@ -30,6 +30,8 @@ import swipe from './navigations/swipe.js';
|
|
|
30
30
|
import findElement from './interactions/find.js';
|
|
31
31
|
import clickElement from './interactions/click.js';
|
|
32
32
|
import doubleTap from './interactions/double-tap.js';
|
|
33
|
+
import longPress from './interactions/long-press.js';
|
|
34
|
+
import dragAndDrop from './interactions/drag-and-drop.js';
|
|
33
35
|
import setValue from './interactions/set-value.js';
|
|
34
36
|
import getText from './interactions/get-text.js';
|
|
35
37
|
import getPageSource from './interactions/get-page-source.js';
|
|
@@ -129,6 +131,8 @@ export default function registerTools(server: FastMCP): void {
|
|
|
129
131
|
findElement(server);
|
|
130
132
|
clickElement(server);
|
|
131
133
|
doubleTap(server);
|
|
134
|
+
longPress(server);
|
|
135
|
+
dragAndDrop(server);
|
|
132
136
|
setValue(server);
|
|
133
137
|
getText(server);
|
|
134
138
|
getPageSource(server);
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { FastMCP } from 'fastmcp/dist/FastMCP.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getDriver, getPlatformName } from '../../session-store.js';
|
|
4
|
+
import { elementUUIDScheme } from '../../schema.js';
|
|
5
|
+
|
|
6
|
+
const DROP_PAUSE_DURATION_MS = 150;
|
|
7
|
+
|
|
8
|
+
async function performDragAndDrop(
|
|
9
|
+
driver: any,
|
|
10
|
+
startX: number,
|
|
11
|
+
startY: number,
|
|
12
|
+
endX: number,
|
|
13
|
+
endY: number,
|
|
14
|
+
duration: number,
|
|
15
|
+
longPressDuration: number
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
await driver.performActions([
|
|
18
|
+
{
|
|
19
|
+
type: 'pointer',
|
|
20
|
+
id: 'finger1',
|
|
21
|
+
parameters: { pointerType: 'touch' },
|
|
22
|
+
actions: [
|
|
23
|
+
{ type: 'pointerMove', duration: 0, x: startX, y: startY },
|
|
24
|
+
{ type: 'pointerDown', button: 0 },
|
|
25
|
+
{ type: 'pause', duration: longPressDuration },
|
|
26
|
+
{ type: 'pointerMove', duration: duration, x: endX, y: endY },
|
|
27
|
+
{ type: 'pause', duration: DROP_PAUSE_DURATION_MS },
|
|
28
|
+
{ type: 'pointerUp', button: 0 },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default function dragAndDrop(server: FastMCP): void {
|
|
35
|
+
const dragAndDropSchema = z.object({
|
|
36
|
+
sourceElementUUID: elementUUIDScheme
|
|
37
|
+
.trim()
|
|
38
|
+
.min(1)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe(
|
|
41
|
+
'UUID of the source element to drag from. Either sourceElementUUID or sourceX/sourceY must be provided.'
|
|
42
|
+
),
|
|
43
|
+
sourceX: z
|
|
44
|
+
.number()
|
|
45
|
+
.int()
|
|
46
|
+
.min(0)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe(
|
|
49
|
+
'Starting X coordinate. Required if sourceElementUUID is not provided.'
|
|
50
|
+
),
|
|
51
|
+
sourceY: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(0)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe(
|
|
57
|
+
'Starting Y coordinate. Required if sourceElementUUID is not provided.'
|
|
58
|
+
),
|
|
59
|
+
targetElementUUID: elementUUIDScheme
|
|
60
|
+
.trim()
|
|
61
|
+
.min(1)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe(
|
|
64
|
+
'UUID of the target element to drop on. Either targetElementUUID or targetX/targetY must be provided.'
|
|
65
|
+
),
|
|
66
|
+
targetX: z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.min(0)
|
|
70
|
+
.optional()
|
|
71
|
+
.describe(
|
|
72
|
+
'Ending X coordinate. Required if targetElementUUID is not provided.'
|
|
73
|
+
),
|
|
74
|
+
targetY: z
|
|
75
|
+
.number()
|
|
76
|
+
.int()
|
|
77
|
+
.min(0)
|
|
78
|
+
.optional()
|
|
79
|
+
.describe(
|
|
80
|
+
'Ending Y coordinate. Required if targetElementUUID is not provided.'
|
|
81
|
+
),
|
|
82
|
+
duration: z
|
|
83
|
+
.number()
|
|
84
|
+
.int()
|
|
85
|
+
.min(100)
|
|
86
|
+
.max(5000)
|
|
87
|
+
.default(1200)
|
|
88
|
+
.optional()
|
|
89
|
+
.describe(
|
|
90
|
+
'Duration of the drag movement in milliseconds. Default is 1200ms.'
|
|
91
|
+
),
|
|
92
|
+
longPressDuration: z
|
|
93
|
+
.number()
|
|
94
|
+
.int()
|
|
95
|
+
.min(400)
|
|
96
|
+
.max(2000)
|
|
97
|
+
.default(600)
|
|
98
|
+
.optional()
|
|
99
|
+
.describe(
|
|
100
|
+
'Duration of the long press before dragging in milliseconds. Default is 600ms.'
|
|
101
|
+
),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
server.addTool({
|
|
105
|
+
name: 'appium_drag_and_drop',
|
|
106
|
+
description: `Perform a drag and drop gesture from a source location to a target location.
|
|
107
|
+
The gesture includes:
|
|
108
|
+
1. Long press (default 600ms, configurable) on the source to initiate drag mode
|
|
109
|
+
2. While holding, drag to the target location
|
|
110
|
+
3. Release at the target to complete the drop
|
|
111
|
+
|
|
112
|
+
Supports four modes:
|
|
113
|
+
1. Element to Element: Drag from one element to another element
|
|
114
|
+
2. Element to Coordinates: Drag from an element to specific coordinates
|
|
115
|
+
3. Coordinates to Element: Drag from coordinates to an element
|
|
116
|
+
4. Coordinates to Coordinates: Drag from coordinates to coordinates
|
|
117
|
+
|
|
118
|
+
This is useful for reordering lists, moving items, drag-to-delete, and other drag interactions.`,
|
|
119
|
+
parameters: dragAndDropSchema,
|
|
120
|
+
annotations: {
|
|
121
|
+
readOnlyHint: false,
|
|
122
|
+
openWorldHint: false,
|
|
123
|
+
},
|
|
124
|
+
execute: async (args: any, context: any): Promise<any> => {
|
|
125
|
+
const driver = getDriver();
|
|
126
|
+
if (!driver) {
|
|
127
|
+
throw new Error('No driver found');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const platform = getPlatformName(driver);
|
|
132
|
+
const duration = args.duration || 1200;
|
|
133
|
+
const longPressDuration = args.longPressDuration || 600;
|
|
134
|
+
|
|
135
|
+
if (
|
|
136
|
+
!args.sourceElementUUID &&
|
|
137
|
+
(args.sourceX === undefined || args.sourceY === undefined)
|
|
138
|
+
) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
'Either sourceElementUUID or both sourceX and sourceY must be provided.'
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
!args.targetElementUUID &&
|
|
146
|
+
(args.targetX === undefined || args.targetY === undefined)
|
|
147
|
+
) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
'Either targetElementUUID or both targetX and targetY must be provided.'
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let startX: number, startY: number;
|
|
154
|
+
let endX: number, endY: number;
|
|
155
|
+
|
|
156
|
+
if (args.sourceElementUUID) {
|
|
157
|
+
const rect = await driver.getElementRect(args.sourceElementUUID);
|
|
158
|
+
startX = Math.floor(rect.x + rect.width / 2);
|
|
159
|
+
startY = Math.floor(rect.y + rect.height / 2);
|
|
160
|
+
} else {
|
|
161
|
+
startX = args.sourceX;
|
|
162
|
+
startY = args.sourceY;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (args.targetElementUUID) {
|
|
166
|
+
const rect = await driver.getElementRect(args.targetElementUUID);
|
|
167
|
+
endX = Math.floor(rect.x + rect.width / 2);
|
|
168
|
+
endY = Math.floor(rect.y + rect.height / 2);
|
|
169
|
+
} else {
|
|
170
|
+
endX = args.targetX;
|
|
171
|
+
endY = args.targetY;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const { width, height } = await driver.getWindowSize();
|
|
175
|
+
if (startX < 0 || startX >= width || startY < 0 || startY >= height) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Source coordinates (${startX}, ${startY}) are out of screen bounds (${width}x${height})`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
if (endX < 0 || endX >= width || endY < 0 || endY >= height) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`Target coordinates (${endX}, ${endY}) are out of screen bounds (${width}x${height})`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (platform === 'Android' || platform === 'iOS') {
|
|
187
|
+
await performDragAndDrop(
|
|
188
|
+
driver,
|
|
189
|
+
startX,
|
|
190
|
+
startY,
|
|
191
|
+
endX,
|
|
192
|
+
endY,
|
|
193
|
+
duration,
|
|
194
|
+
longPressDuration
|
|
195
|
+
);
|
|
196
|
+
} else {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Unsupported platform: ${platform}. Only Android and iOS are supported.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const sourceDesc = args.sourceElementUUID
|
|
203
|
+
? `element ${args.sourceElementUUID}`
|
|
204
|
+
: `coordinates (${startX}, ${startY})`;
|
|
205
|
+
const targetDesc = args.targetElementUUID
|
|
206
|
+
? `element ${args.targetElementUUID}`
|
|
207
|
+
: `coordinates (${endX}, ${endY})`;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
content: [
|
|
211
|
+
{
|
|
212
|
+
type: 'text',
|
|
213
|
+
text: `Successfully performed drag and drop from ${sourceDesc} to ${targetDesc}.`,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
} catch (err: any) {
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: 'text',
|
|
222
|
+
text: `Failed to perform drag and drop. Error: ${err.toString()}`,
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { FastMCP } from 'fastmcp/dist/FastMCP.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getDriver, getPlatformName } from '../../session-store.js';
|
|
4
|
+
import { elementUUIDScheme } from '../../schema.js';
|
|
5
|
+
|
|
6
|
+
export default function longPress(server: FastMCP): void {
|
|
7
|
+
const longPressSchema = z.object({
|
|
8
|
+
elementUUID: elementUUIDScheme,
|
|
9
|
+
duration: z
|
|
10
|
+
.number()
|
|
11
|
+
.int()
|
|
12
|
+
.min(500)
|
|
13
|
+
.max(10000)
|
|
14
|
+
.default(2000)
|
|
15
|
+
.optional()
|
|
16
|
+
.describe(
|
|
17
|
+
'Duration of the long press in milliseconds. Default is 2000ms.'
|
|
18
|
+
),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
server.addTool({
|
|
22
|
+
name: 'appium_long_press',
|
|
23
|
+
description: 'Perform a long press (press and hold) gesture on an element',
|
|
24
|
+
parameters: longPressSchema,
|
|
25
|
+
annotations: {
|
|
26
|
+
readOnlyHint: false,
|
|
27
|
+
openWorldHint: false,
|
|
28
|
+
},
|
|
29
|
+
execute: async (args: any, context: any): Promise<any> => {
|
|
30
|
+
const driver = getDriver();
|
|
31
|
+
if (!driver) {
|
|
32
|
+
throw new Error('No driver found');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const platform = getPlatformName(driver);
|
|
37
|
+
const duration = args.duration || 2000;
|
|
38
|
+
|
|
39
|
+
if (platform === 'Android') {
|
|
40
|
+
const rect = await driver.getElementRect(args.elementUUID);
|
|
41
|
+
const x = Math.floor(rect.x + rect.width / 2);
|
|
42
|
+
const y = Math.floor(rect.y + rect.height / 2);
|
|
43
|
+
|
|
44
|
+
await driver.performActions([
|
|
45
|
+
{
|
|
46
|
+
type: 'pointer',
|
|
47
|
+
id: 'finger1',
|
|
48
|
+
parameters: { pointerType: 'touch' },
|
|
49
|
+
actions: [
|
|
50
|
+
{ type: 'pointerMove', duration: 0, x, y },
|
|
51
|
+
{ type: 'pointerDown', button: 0 },
|
|
52
|
+
{ type: 'pause', duration: duration },
|
|
53
|
+
{ type: 'pointerUp', button: 0 },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
} else if (platform === 'iOS') {
|
|
58
|
+
try {
|
|
59
|
+
await driver.execute('mobile: touchAndHold', {
|
|
60
|
+
elementId: args.elementUUID,
|
|
61
|
+
duration: duration / 1000,
|
|
62
|
+
});
|
|
63
|
+
} catch (touchAndHoldError) {
|
|
64
|
+
const rect = await driver.getElementRect(args.elementUUID);
|
|
65
|
+
const x = Math.floor(rect.x + rect.width / 2);
|
|
66
|
+
const y = Math.floor(rect.y + rect.height / 2);
|
|
67
|
+
|
|
68
|
+
await driver.performActions([
|
|
69
|
+
{
|
|
70
|
+
type: 'pointer',
|
|
71
|
+
id: 'finger1',
|
|
72
|
+
parameters: { pointerType: 'touch' },
|
|
73
|
+
actions: [
|
|
74
|
+
{ type: 'pointerMove', duration: 0, x, y },
|
|
75
|
+
{ type: 'pointerDown', button: 0 },
|
|
76
|
+
{ type: 'pause', duration: duration },
|
|
77
|
+
{ type: 'pointerUp', button: 0 },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Unsupported platform: ${platform}. Only Android and iOS are supported.`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: 'text',
|
|
92
|
+
text: `Successfully performed long press on element ${args.elementUUID}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
} catch (err: any) {
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: `Failed to perform long press on element ${args.elementUUID}. err: ${err.toString()}`,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|