appium-mcp 1.84.0 → 1.84.2
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/dist/command.d.ts +9 -0
- package/dist/command.d.ts.map +1 -1
- package/dist/command.js +29 -0
- package/dist/command.js.map +1 -1
- package/dist/tools/interactions/find.d.ts.map +1 -1
- package/dist/tools/interactions/find.js +2 -1
- package/dist/tools/interactions/find.js.map +1 -1
- package/package.json +2 -1
- package/server.json +2 -2
- package/src/command.ts +37 -0
- package/src/tools/interactions/find.ts +6 -1
- package/dist/tests/__mocks__/@appium/support.d.ts +0 -92
- package/dist/tests/__mocks__/@appium/support.d.ts.map +0 -1
- package/dist/tests/__mocks__/@appium/support.js +0 -66
- package/dist/tests/__mocks__/@appium/support.js.map +0 -1
- package/dist/tests/benchmark_model/benchmark_model.d.ts +0 -3
- package/dist/tests/benchmark_model/benchmark_model.d.ts.map +0 -1
- package/dist/tests/benchmark_model/benchmark_model.js +0 -617
- package/dist/tests/benchmark_model/benchmark_model.js.map +0 -1
- package/dist/tests/create-server.test.d.ts +0 -2
- package/dist/tests/create-server.test.d.ts.map +0 -1
- package/dist/tests/create-server.test.js +0 -586
- package/dist/tests/create-server.test.js.map +0 -1
- package/dist/tests/generate-all-locators.test.d.ts +0 -2
- package/dist/tests/generate-all-locators.test.d.ts.map +0 -1
- package/dist/tests/generate-all-locators.test.js +0 -136
- package/dist/tests/generate-all-locators.test.js.map +0 -1
- package/dist/tests/persistence.test.d.ts +0 -2
- package/dist/tests/persistence.test.d.ts.map +0 -1
- package/dist/tests/persistence.test.js +0 -116
- package/dist/tests/persistence.test.js.map +0 -1
- package/dist/tests/plugin.test.d.ts +0 -2
- package/dist/tests/plugin.test.d.ts.map +0 -1
- package/dist/tests/plugin.test.js +0 -399
- package/dist/tests/plugin.test.js.map +0 -1
- package/dist/tests/policy.test.d.ts +0 -2
- package/dist/tests/policy.test.d.ts.map +0 -1
- package/dist/tests/policy.test.js +0 -44
- package/dist/tests/policy.test.js.map +0 -1
- package/dist/tests/screenshot.test.d.ts +0 -2
- package/dist/tests/screenshot.test.d.ts.map +0 -1
- package/dist/tests/screenshot.test.js +0 -243
- package/dist/tests/screenshot.test.js.map +0 -1
- package/dist/tests/session-store.test.d.ts +0 -2
- package/dist/tests/session-store.test.d.ts.map +0 -1
- package/dist/tests/session-store.test.js +0 -459
- package/dist/tests/session-store.test.js.map +0 -1
- package/dist/tests/test-setup-wda.d.ts +0 -2
- package/dist/tests/test-setup-wda.d.ts.map +0 -1
- package/dist/tests/test-setup-wda.js +0 -199
- package/dist/tests/test-setup-wda.js.map +0 -1
- package/dist/tests/tools/evidence.test.d.ts +0 -2
- package/dist/tests/tools/evidence.test.d.ts.map +0 -1
- package/dist/tests/tools/evidence.test.js +0 -158
- package/dist/tests/tools/evidence.test.js.map +0 -1
- package/dist/tests/tools/gestures/ai-element.test.d.ts +0 -2
- package/dist/tests/tools/gestures/ai-element.test.d.ts.map +0 -1
- package/dist/tests/tools/gestures/ai-element.test.js +0 -114
- package/dist/tests/tools/gestures/ai-element.test.js.map +0 -1
- package/dist/tests/tools/gestures/swipe-scroll.test.d.ts +0 -2
- package/dist/tests/tools/gestures/swipe-scroll.test.d.ts.map +0 -1
- package/dist/tests/tools/gestures/swipe-scroll.test.js +0 -63
- package/dist/tests/tools/gestures/swipe-scroll.test.js.map +0 -1
- package/dist/tests/tools/interactions/webdriver-ai-element-rejection.test.d.ts +0 -2
- package/dist/tests/tools/interactions/webdriver-ai-element-rejection.test.d.ts.map +0 -1
- package/dist/tests/tools/interactions/webdriver-ai-element-rejection.test.js +0 -94
- package/dist/tests/tools/interactions/webdriver-ai-element-rejection.test.js.map +0 -1
- package/dist/tests/tools/llm-wording.test.d.ts +0 -2
- package/dist/tests/tools/llm-wording.test.d.ts.map +0 -1
- package/dist/tests/tools/llm-wording.test.js +0 -89
- package/dist/tests/tools/llm-wording.test.js.map +0 -1
- package/dist/tests/tools/session/device-info.test.d.ts +0 -2
- package/dist/tests/tools/session/device-info.test.d.ts.map +0 -1
- package/dist/tests/tools/session/device-info.test.js +0 -144
- package/dist/tests/tools/session/device-info.test.js.map +0 -1
- package/dist/tests/tools/session/file-transfer.test.d.ts +0 -2
- package/dist/tests/tools/session/file-transfer.test.d.ts.map +0 -1
- package/dist/tests/tools/session/file-transfer.test.js +0 -98
- package/dist/tests/tools/session/file-transfer.test.js.map +0 -1
- package/dist/tests/tools/session/session.test.d.ts +0 -2
- package/dist/tests/tools/session/session.test.d.ts.map +0 -1
- package/dist/tests/tools/session/session.test.js +0 -413
- package/dist/tests/tools/session/session.test.js.map +0 -1
- package/dist/tests/utils/collection.test.d.ts +0 -2
- package/dist/tests/utils/collection.test.d.ts.map +0 -1
- package/dist/tests/utils/collection.test.js +0 -87
- package/dist/tests/utils/collection.test.js.map +0 -1
- package/dist/tests/utils/paths.test.d.ts +0 -2
- package/dist/tests/utils/paths.test.d.ts.map +0 -1
- package/dist/tests/utils/paths.test.js +0 -21
- package/dist/tests/utils/paths.test.js.map +0 -1
- package/dist/tests/verify.test.d.ts +0 -2
- package/dist/tests/verify.test.d.ts.map +0 -1
- package/dist/tests/verify.test.js +0 -148
- package/dist/tests/verify.test.js.map +0 -1
- package/dist/tests/vision-finder.test.d.ts +0 -10
- package/dist/tests/vision-finder.test.d.ts.map +0 -1
- package/dist/tests/vision-finder.test.js +0 -420
- package/dist/tests/vision-finder.test.js.map +0 -1
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from '@jest/globals';
|
|
2
|
-
import { generateAllElementLocators } from '../locators/generate-all-locators.js';
|
|
3
|
-
describe('generateAllElementLocators', () => {
|
|
4
|
-
// Sample XML for testing
|
|
5
|
-
const sampleXML = `
|
|
6
|
-
<hierarchy>
|
|
7
|
-
<android.widget.FrameLayout resource-id="android:id/content">
|
|
8
|
-
<android.widget.LinearLayout>
|
|
9
|
-
<android.widget.TextView text="Hello World" resource-id="com.example:id/text_view" clickable="true" enabled="true" displayed="true" />
|
|
10
|
-
<android.widget.Button text="Click Me" resource-id="com.example:id/button" clickable="true" enabled="true" displayed="true" />
|
|
11
|
-
<android.widget.EditText text="" resource-id="com.example:id/edit_text" clickable="true" enabled="true" displayed="true" />
|
|
12
|
-
</android.widget.LinearLayout>
|
|
13
|
-
</android.widget.FrameLayout>
|
|
14
|
-
</hierarchy>
|
|
15
|
-
`;
|
|
16
|
-
// Sample iOS XML for testing
|
|
17
|
-
const sampleIOSXML = `
|
|
18
|
-
<hierarchy>
|
|
19
|
-
<XCUIElementTypeApplication>
|
|
20
|
-
<XCUIElementTypeWindow>
|
|
21
|
-
<XCUIElementTypeButton name="Click Me" enabled="true" visible="true" />
|
|
22
|
-
<XCUIElementTypeTextField name="Enter text" enabled="true" visible="true" />
|
|
23
|
-
<XCUIElementTypeStaticText name="Hello World" enabled="true" visible="true" />
|
|
24
|
-
</XCUIElementTypeWindow>
|
|
25
|
-
</XCUIElementTypeApplication>
|
|
26
|
-
</hierarchy>
|
|
27
|
-
`;
|
|
28
|
-
test('should return an array when given valid XML', () => {
|
|
29
|
-
// Call the function with the sample XML
|
|
30
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2');
|
|
31
|
-
// Basic validation of the result
|
|
32
|
-
expect(Array.isArray(result)).toBe(true);
|
|
33
|
-
expect(result.length).toBeGreaterThan(0);
|
|
34
|
-
// Verify the structure of the returned elements
|
|
35
|
-
if (result.length > 0) {
|
|
36
|
-
const element = result[0];
|
|
37
|
-
expect(element).toHaveProperty('tagName');
|
|
38
|
-
expect(element).toHaveProperty('locators');
|
|
39
|
-
expect(element).toHaveProperty('text');
|
|
40
|
-
expect(element).toHaveProperty('contentDesc');
|
|
41
|
-
expect(element).toHaveProperty('resourceId');
|
|
42
|
-
expect(element).toHaveProperty('clickable');
|
|
43
|
-
expect(element).toHaveProperty('enabled');
|
|
44
|
-
expect(element).toHaveProperty('displayed');
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
test('should return an empty array when given invalid XML', () => {
|
|
48
|
-
// Call the function with invalid XML (just a root element with no content)
|
|
49
|
-
const result = generateAllElementLocators('<hierarchy></hierarchy>', true, 'uiautomator2');
|
|
50
|
-
// Verify the result is an empty array or at least doesn't throw an error
|
|
51
|
-
expect(Array.isArray(result)).toBe(true);
|
|
52
|
-
expect(result.length).toBe(0);
|
|
53
|
-
});
|
|
54
|
-
test('should apply includeTagNames filter correctly', () => {
|
|
55
|
-
// Call the function with filters
|
|
56
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2', {
|
|
57
|
-
includeTagNames: ['android.widget.Button'],
|
|
58
|
-
});
|
|
59
|
-
// If the filter works, either the result will be empty (if no buttons found)
|
|
60
|
-
// or all elements will be buttons
|
|
61
|
-
if (result.length > 0) {
|
|
62
|
-
expect(result.every((element) => element.tagName.includes('Button'))).toBe(true);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
test('should apply excludeTagNames filter correctly', () => {
|
|
66
|
-
// Call the function with excludeTagNames filter
|
|
67
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2', {
|
|
68
|
-
excludeTagNames: ['android.widget.Button'],
|
|
69
|
-
});
|
|
70
|
-
// Verify no Button elements are included
|
|
71
|
-
expect(result.every((element) => !element.tagName.includes('Button'))).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
test('should apply minAttributeCount filter correctly', () => {
|
|
74
|
-
// Call the function with minAttributeCount filter
|
|
75
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2', {
|
|
76
|
-
minAttributeCount: 3,
|
|
77
|
-
});
|
|
78
|
-
// All elements should have at least 3 attributes
|
|
79
|
-
if (result.length > 0) {
|
|
80
|
-
// We can't directly check the attributes count since we only have the processed elements
|
|
81
|
-
// But we can verify that elements with fewer attributes are filtered out
|
|
82
|
-
expect(result.length).toBeLessThanOrEqual(generateAllElementLocators(sampleXML, true, 'uiautomator2').length);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
test('should handle fetchableOnly filter for Android', () => {
|
|
86
|
-
// Call the function with fetchableOnly filter
|
|
87
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2', {
|
|
88
|
-
fetchableOnly: true,
|
|
89
|
-
});
|
|
90
|
-
// Verify the result contains only interactable elements
|
|
91
|
-
if (result.length > 0) {
|
|
92
|
-
const interactableTags = [
|
|
93
|
-
'EditText',
|
|
94
|
-
'Button',
|
|
95
|
-
'ImageButton',
|
|
96
|
-
'CheckBox',
|
|
97
|
-
'RadioButton',
|
|
98
|
-
'Switch',
|
|
99
|
-
'ToggleButton',
|
|
100
|
-
'TextView',
|
|
101
|
-
];
|
|
102
|
-
expect(result.every((element) => interactableTags.some((tag) => element.tagName.includes(tag)) ||
|
|
103
|
-
element.clickable === true)).toBe(true);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
test('should handle fetchableOnly filter for iOS', () => {
|
|
107
|
-
// Call the function with fetchableOnly filter for iOS
|
|
108
|
-
const result = generateAllElementLocators(sampleIOSXML, true, 'xcuitest', {
|
|
109
|
-
fetchableOnly: true,
|
|
110
|
-
});
|
|
111
|
-
// Verify the result contains only interactable iOS elements
|
|
112
|
-
if (result.length > 0) {
|
|
113
|
-
const interactableTags = [
|
|
114
|
-
'XCUIElementTypeTextField',
|
|
115
|
-
'XCUIElementTypeSecureTextField',
|
|
116
|
-
'XCUIElementTypeButton',
|
|
117
|
-
'XCUIElementTypeImage',
|
|
118
|
-
'XCUIElementTypeSwitch',
|
|
119
|
-
'XCUIElementTypeStaticText',
|
|
120
|
-
'XCUIElementTypeTextView',
|
|
121
|
-
'XCUIElementTypeCell',
|
|
122
|
-
'XCUIElementTypeLink',
|
|
123
|
-
];
|
|
124
|
-
expect(result.every((element) => interactableTags.some((tag) => element.tagName.includes(tag)))).toBe(true);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
test('should handle clickableOnly filter correctly', () => {
|
|
128
|
-
// Call the function with clickableOnly filter
|
|
129
|
-
const result = generateAllElementLocators(sampleXML, true, 'uiautomator2', {
|
|
130
|
-
clickableOnly: true,
|
|
131
|
-
});
|
|
132
|
-
// Verify all elements are clickable
|
|
133
|
-
expect(result.every((element) => element.clickable === true)).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
//# sourceMappingURL=generate-all-locators.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"generate-all-locators.test.js","sourceRoot":"","sources":["../../src/tests/generate-all-locators.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.test.d.ts","sourceRoot":"","sources":["../../src/tests/persistence.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, test } from '@jest/globals';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
|
-
import { constants } from 'node:fs';
|
|
4
|
-
import { access, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
5
|
-
import os from 'node:os';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { readAllPersistedSessions, } from '../persistence.js';
|
|
8
|
-
const originalPersistencePath = process.env.APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATH;
|
|
9
|
-
const tempDirs = [];
|
|
10
|
-
afterEach(async () => {
|
|
11
|
-
if (originalPersistencePath === undefined) {
|
|
12
|
-
delete process.env.APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATH;
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
process.env.APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATH =
|
|
16
|
-
originalPersistencePath;
|
|
17
|
-
}
|
|
18
|
-
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
|
19
|
-
});
|
|
20
|
-
describe('readAllPersistedSessions', () => {
|
|
21
|
-
test('skips a legacy file when the canonical hashed file also exists', async () => {
|
|
22
|
-
const dir = await createTempPersistenceDir();
|
|
23
|
-
const sessionId = 'session-123';
|
|
24
|
-
const staleLegacy = persistedSession(sessionId, 'http://stale.example');
|
|
25
|
-
const canonical = persistedSession(sessionId, 'http://valid.example');
|
|
26
|
-
await writeSessionFile(dir, `${sessionId}.json`, staleLegacy);
|
|
27
|
-
await writeSessionFile(dir, hashedSessionFilename(sessionId), canonical);
|
|
28
|
-
const sessions = await readAllPersistedSessions();
|
|
29
|
-
expect(sessions).toHaveLength(1);
|
|
30
|
-
expect(sessions[0]).toMatchObject({
|
|
31
|
-
sessionId,
|
|
32
|
-
remoteServerUrl: 'http://valid.example',
|
|
33
|
-
});
|
|
34
|
-
await expectFileMissing(path.join(dir, `${sessionId}.json`));
|
|
35
|
-
await expectCanonicalSession(dir, sessionId, 'http://valid.example');
|
|
36
|
-
});
|
|
37
|
-
test('removes a non-canonical duplicate when the canonical file also exists', async () => {
|
|
38
|
-
const dir = await createTempPersistenceDir();
|
|
39
|
-
const sessionId = 'session-456';
|
|
40
|
-
const staleDuplicate = persistedSession(sessionId, 'http://stale.example');
|
|
41
|
-
const canonical = persistedSession(sessionId, 'http://valid.example');
|
|
42
|
-
await writeSessionFile(dir, 'duplicate-session.json', staleDuplicate);
|
|
43
|
-
await writeSessionFile(dir, hashedSessionFilename(sessionId), canonical);
|
|
44
|
-
const sessions = await readAllPersistedSessions();
|
|
45
|
-
expect(sessions).toHaveLength(1);
|
|
46
|
-
expect(sessions[0]).toMatchObject({
|
|
47
|
-
sessionId,
|
|
48
|
-
remoteServerUrl: 'http://valid.example',
|
|
49
|
-
});
|
|
50
|
-
await expectFileMissing(path.join(dir, 'duplicate-session.json'));
|
|
51
|
-
await expectCanonicalSession(dir, sessionId, 'http://valid.example');
|
|
52
|
-
});
|
|
53
|
-
test('coalesces non-canonical duplicates when no canonical file exists yet', async () => {
|
|
54
|
-
const dir = await createTempPersistenceDir();
|
|
55
|
-
const sessionId = 'session-789';
|
|
56
|
-
await writeSessionFile(dir, `${sessionId}.json`, persistedSession(sessionId, 'http://legacy.example'));
|
|
57
|
-
await writeSessionFile(dir, 'duplicate-session.json', persistedSession(sessionId, 'http://duplicate.example'));
|
|
58
|
-
const sessions = await readAllPersistedSessions();
|
|
59
|
-
expect(sessions).toHaveLength(1);
|
|
60
|
-
expect(sessions[0]?.sessionId).toBe(sessionId);
|
|
61
|
-
expect(['http://legacy.example', 'http://duplicate.example']).toContain(sessions[0]?.remoteServerUrl);
|
|
62
|
-
await expectFileMissing(path.join(dir, `${sessionId}.json`));
|
|
63
|
-
await expectFileMissing(path.join(dir, 'duplicate-session.json'));
|
|
64
|
-
await expectCanonicalSession(dir, sessionId, sessions[0].remoteServerUrl);
|
|
65
|
-
});
|
|
66
|
-
test('still migrates and returns a legacy file when no canonical file exists', async () => {
|
|
67
|
-
const dir = await createTempPersistenceDir();
|
|
68
|
-
const sessionId = 'legacy-session';
|
|
69
|
-
const legacy = persistedSession(sessionId, 'http://legacy.example');
|
|
70
|
-
await writeSessionFile(dir, `${sessionId}.json`, legacy);
|
|
71
|
-
const sessions = await readAllPersistedSessions();
|
|
72
|
-
expect(sessions).toHaveLength(1);
|
|
73
|
-
expect(sessions[0]).toMatchObject({
|
|
74
|
-
sessionId,
|
|
75
|
-
remoteServerUrl: 'http://legacy.example',
|
|
76
|
-
});
|
|
77
|
-
await expectFileMissing(path.join(dir, `${sessionId}.json`));
|
|
78
|
-
await expectCanonicalSession(dir, sessionId, 'http://legacy.example');
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
async function createTempPersistenceDir() {
|
|
82
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'appium-mcp-sessions-'));
|
|
83
|
-
tempDirs.push(dir);
|
|
84
|
-
process.env.APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATH = dir;
|
|
85
|
-
return dir;
|
|
86
|
-
}
|
|
87
|
-
async function writeSessionFile(dir, name, session) {
|
|
88
|
-
await writeFile(path.join(dir, name), JSON.stringify(session, null, 2));
|
|
89
|
-
}
|
|
90
|
-
function persistedSession(sessionId, remoteServerUrl) {
|
|
91
|
-
return {
|
|
92
|
-
sessionId,
|
|
93
|
-
remoteServerUrl,
|
|
94
|
-
capabilities: { platformName: 'Android' },
|
|
95
|
-
platform: 'Android',
|
|
96
|
-
automationName: 'UiAutomator2',
|
|
97
|
-
deviceName: 'Pixel',
|
|
98
|
-
ownership: 'attached',
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function hashedSessionFilename(sessionId) {
|
|
102
|
-
return `${createHash('sha256').update(sessionId).digest('hex')}.json`;
|
|
103
|
-
}
|
|
104
|
-
async function expectFileExists(filePath) {
|
|
105
|
-
await expect(access(filePath, constants.F_OK)).resolves.toBeUndefined();
|
|
106
|
-
}
|
|
107
|
-
async function expectFileMissing(filePath) {
|
|
108
|
-
await expect(access(filePath, constants.F_OK)).rejects.toThrow();
|
|
109
|
-
}
|
|
110
|
-
async function expectCanonicalSession(dir, sessionId, remoteServerUrl) {
|
|
111
|
-
const filePath = path.join(dir, hashedSessionFilename(sessionId));
|
|
112
|
-
await expectFileExists(filePath);
|
|
113
|
-
const raw = await readFile(filePath, 'utf8');
|
|
114
|
-
expect(JSON.parse(raw)).toMatchObject({ sessionId, remoteServerUrl });
|
|
115
|
-
}
|
|
116
|
-
//# sourceMappingURL=persistence.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.test.js","sourceRoot":"","sources":["../../src/tests/persistence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.test.d.ts","sourceRoot":"","sources":["../../src/tests/plugin.test.ts"],"names":[],"mappings":""}
|