appium-uiautomator2-driver 2.42.2 → 2.43.1
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 +14 -0
- package/build/lib/commands/actions.d.ts +22 -1
- package/build/lib/commands/actions.d.ts.map +1 -1
- package/build/lib/commands/actions.js +30 -62
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +28 -1
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +42 -23
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +19 -0
- package/build/lib/commands/app-management.d.ts.map +1 -0
- package/build/lib/commands/app-management.js +45 -0
- package/build/lib/commands/app-management.js.map +1 -0
- package/build/lib/commands/app-strings.d.ts +9 -0
- package/build/lib/commands/app-strings.d.ts.map +1 -1
- package/build/lib/commands/app-strings.js +11 -79
- package/build/lib/commands/app-strings.js.map +1 -1
- package/build/lib/commands/battery.d.ts +7 -0
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +14 -20
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/element.d.ts +100 -1
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +175 -125
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +25 -0
- package/build/lib/commands/execute.d.ts.map +1 -0
- package/build/lib/commands/execute.js +109 -0
- package/build/lib/commands/execute.js.map +1 -0
- package/build/lib/commands/find.d.ts +10 -0
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +25 -27
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/gestures.d.ts +103 -1
- package/build/lib/commands/gestures.d.ts.map +1 -1
- package/build/lib/commands/gestures.js +202 -173
- package/build/lib/commands/gestures.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +47 -0
- package/build/lib/commands/keyboard.d.ts.map +1 -0
- package/build/lib/commands/keyboard.js +92 -0
- package/build/lib/commands/keyboard.js.map +1 -0
- package/build/lib/commands/misc.d.ts +48 -0
- package/build/lib/commands/misc.d.ts.map +1 -0
- package/build/lib/commands/misc.js +75 -0
- package/build/lib/commands/misc.js.map +1 -0
- package/build/lib/commands/navigation.d.ts +20 -0
- package/build/lib/commands/navigation.d.ts.map +1 -0
- package/build/lib/commands/navigation.js +35 -0
- package/build/lib/commands/navigation.js.map +1 -0
- package/build/lib/commands/screenshot.d.ts +24 -1
- package/build/lib/commands/screenshot.d.ts.map +1 -1
- package/build/lib/commands/screenshot.js +87 -64
- package/build/lib/commands/screenshot.js.map +1 -1
- package/build/lib/commands/touch.d.ts +81 -0
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +158 -41
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/viewport.d.ts +37 -1
- package/build/lib/commands/viewport.d.ts.map +1 -1
- package/build/lib/commands/viewport.js +80 -36
- package/build/lib/commands/viewport.js.map +1 -1
- package/build/lib/driver.d.ts +94 -24
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +114 -28
- package/build/lib/driver.js.map +1 -1
- package/build/lib/helpers.d.ts +12 -6
- package/build/lib/helpers.d.ts.map +1 -1
- package/build/lib/helpers.js +18 -18
- package/build/lib/helpers.js.map +1 -1
- package/build/lib/method-map.d.ts +0 -23
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/uiautomator2.js +3 -3
- package/build/lib/uiautomator2.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/commands/actions.js +37 -114
- package/lib/commands/alert.js +51 -37
- package/lib/commands/app-management.js +42 -0
- package/lib/commands/app-strings.js +9 -89
- package/lib/commands/battery.js +16 -26
- package/lib/commands/element.js +235 -214
- package/lib/commands/execute.js +120 -0
- package/lib/commands/find.js +31 -37
- package/lib/commands/gestures.js +252 -234
- package/lib/commands/keyboard.js +103 -0
- package/lib/commands/misc.js +106 -0
- package/lib/commands/navigation.js +31 -0
- package/lib/commands/screenshot.js +96 -77
- package/lib/commands/touch.js +190 -48
- package/lib/commands/viewport.js +100 -50
- package/lib/driver.ts +225 -36
- package/lib/helpers.js +15 -22
- package/lib/uiautomator2.js +3 -3
- package/npm-shrinkwrap.json +34 -34
- package/package.json +2 -2
- package/build/lib/commands/general.d.ts +0 -4
- package/build/lib/commands/general.d.ts.map +0 -1
- package/build/lib/commands/general.js +0 -214
- package/build/lib/commands/general.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -2
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -14
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/commands/mixins.d.ts +0 -87
- package/build/lib/commands/mixins.d.ts.map +0 -1
- package/build/lib/commands/mixins.js +0 -26
- package/build/lib/commands/mixins.js.map +0 -1
- package/build/lib/utils.d.ts +0 -10
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js +0 -26
- package/build/lib/utils.js.map +0 -1
- package/lib/commands/general.js +0 -289
- package/lib/commands/index.js +0 -11
- package/lib/commands/mixins.ts +0 -169
- package/lib/utils.js +0 -19
package/lib/commands/viewport.js
CHANGED
|
@@ -1,50 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
1
|
+
|
|
2
|
+
// memoized in constructor
|
|
3
|
+
/**
|
|
4
|
+
* @this {AndroidUiautomator2Driver}
|
|
5
|
+
* @returns {Promise<number>}
|
|
6
|
+
*/
|
|
7
|
+
export async function getStatusBarHeight() {
|
|
8
|
+
const {statusBar} = /** @type {{statusBar: number}} */ (
|
|
9
|
+
await /** @type {import('../uiautomator2').UiAutomator2Server} */ (
|
|
10
|
+
this.uiautomator2
|
|
11
|
+
).jwproxy.command(`/appium/device/system_bars`, 'GET', {})
|
|
12
|
+
);
|
|
13
|
+
return statusBar;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// memoized in constructor
|
|
17
|
+
/**
|
|
18
|
+
* @this {AndroidUiautomator2Driver}
|
|
19
|
+
* @returns {Promise<string>}
|
|
20
|
+
*/
|
|
21
|
+
export async function getDevicePixelRatio() {
|
|
22
|
+
return String(
|
|
23
|
+
await /** @type {import('../uiautomator2').UiAutomator2Server} */ (
|
|
24
|
+
this.uiautomator2
|
|
25
|
+
).jwproxy.command('/appium/device/pixel_ratio', 'GET', {})
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @this {AndroidUiautomator2Driver}
|
|
31
|
+
* @returns {Promise<import('./types').RelativeRect>}
|
|
32
|
+
*/
|
|
33
|
+
export async function getViewPortRect() {
|
|
34
|
+
const windowSize = await this.getWindowSize();
|
|
35
|
+
const statusBarHeight = await this.getStatusBarHeight();
|
|
36
|
+
// android returns the upscaled window size, so to get the true size of the
|
|
37
|
+
// rect we have to downscale
|
|
38
|
+
return {
|
|
39
|
+
left: 0,
|
|
40
|
+
top: statusBarHeight,
|
|
41
|
+
width: windowSize.width,
|
|
42
|
+
height: windowSize.height - statusBarHeight,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the viewport coordinates.
|
|
48
|
+
* @this {AndroidUiautomator2Driver}
|
|
49
|
+
* @returns {Promise<import('./types').RelativeRect>} The viewport coordinates.
|
|
50
|
+
*/
|
|
51
|
+
export async function mobileViewPortRect() {
|
|
52
|
+
return await this.getViewPortRect();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// For W3C
|
|
56
|
+
/**
|
|
57
|
+
* @this {AndroidUiautomator2Driver}
|
|
58
|
+
* @returns {Promise<import('@appium/types').Rect>}
|
|
59
|
+
*/
|
|
60
|
+
export async function getWindowRect() {
|
|
61
|
+
const {width, height} = await this.getWindowSize();
|
|
62
|
+
return {
|
|
63
|
+
width,
|
|
64
|
+
height,
|
|
65
|
+
x: 0,
|
|
66
|
+
y: 0,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @this {AndroidUiautomator2Driver}
|
|
72
|
+
* @returns {Promise<number>}
|
|
73
|
+
*/
|
|
74
|
+
export async function getDisplayDensity() {
|
|
75
|
+
return /** @type {number} */ (
|
|
76
|
+
await this.uiautomator2.jwproxy.command(
|
|
77
|
+
'/appium/device/display_density',
|
|
78
|
+
'GET',
|
|
79
|
+
{}
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @this {AndroidUiautomator2Driver}
|
|
86
|
+
* @returns {Promise<import('@appium/types').Size>}
|
|
87
|
+
*/
|
|
88
|
+
export async function getWindowSize() {
|
|
89
|
+
return /** @type {import('@appium/types').Size} */ (
|
|
90
|
+
await this.uiautomator2.jwproxy.command(
|
|
91
|
+
'/window/current/size',
|
|
92
|
+
'GET',
|
|
93
|
+
{}
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @typedef {import('../driver').AndroidUiautomator2Driver} AndroidUiautomator2Driver
|
|
100
|
+
*/
|
package/lib/driver.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
StringRecord,
|
|
11
11
|
} from '@appium/types';
|
|
12
12
|
import {DEFAULT_ADB_PORT} from 'appium-adb';
|
|
13
|
-
import AndroidDriver, {
|
|
13
|
+
import AndroidDriver, {utils} from 'appium-android-driver';
|
|
14
14
|
import {SETTINGS_HELPER_ID} from 'io.appium.settings';
|
|
15
15
|
import {BaseDriver, DeviceSettings} from 'appium/driver';
|
|
16
16
|
import {fs, mjpeg, util} from 'appium/support';
|
|
@@ -24,8 +24,8 @@ import type {ExecError} from 'teen_process';
|
|
|
24
24
|
import UIAUTOMATOR2_CONSTRAINTS, {type Uiautomator2Constraints} from './constraints';
|
|
25
25
|
import {executeMethodMap} from './execute-method-map';
|
|
26
26
|
import {APKS_EXTENSION, APK_EXTENSION} from './extensions';
|
|
27
|
-
import uiautomator2Helpers from './helpers';
|
|
28
27
|
import {newMethodMap} from './method-map';
|
|
28
|
+
import { signApp } from './helpers';
|
|
29
29
|
import type { EmptyObject } from 'type-fest';
|
|
30
30
|
import type {
|
|
31
31
|
Uiautomator2Settings,
|
|
@@ -38,8 +38,115 @@ import type {
|
|
|
38
38
|
W3CUiautomator2DriverCaps,
|
|
39
39
|
} from './types';
|
|
40
40
|
import {SERVER_PACKAGE_ID, SERVER_TEST_PACKAGE_ID, UiAutomator2Server} from './uiautomator2';
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
import {
|
|
42
|
+
mobileGetActionHistory,
|
|
43
|
+
mobileScheduleAction,
|
|
44
|
+
mobileUnscheduleAction,
|
|
45
|
+
} from './commands/actions';
|
|
46
|
+
import {
|
|
47
|
+
getAlertText,
|
|
48
|
+
mobileAcceptAlert,
|
|
49
|
+
mobileDismissAlert,
|
|
50
|
+
postAcceptAlert,
|
|
51
|
+
postDismissAlert,
|
|
52
|
+
} from './commands/alert';
|
|
53
|
+
import {
|
|
54
|
+
mobileInstallMultipleApks,
|
|
55
|
+
mobileBackgroundApp,
|
|
56
|
+
} from './commands/app-management';
|
|
57
|
+
import {
|
|
58
|
+
mobileGetAppStrings,
|
|
59
|
+
} from './commands/app-strings';
|
|
60
|
+
import {
|
|
61
|
+
mobileGetBatteryInfo,
|
|
62
|
+
} from './commands/battery';
|
|
63
|
+
import {
|
|
64
|
+
active,
|
|
65
|
+
getAttribute,
|
|
66
|
+
elementEnabled,
|
|
67
|
+
elementDisplayed,
|
|
68
|
+
elementSelected,
|
|
69
|
+
getName,
|
|
70
|
+
getLocation,
|
|
71
|
+
getSize,
|
|
72
|
+
getElementRect,
|
|
73
|
+
getElementScreenshot,
|
|
74
|
+
getText,
|
|
75
|
+
setValueImmediate,
|
|
76
|
+
doSetElementValue,
|
|
77
|
+
click,
|
|
78
|
+
clear,
|
|
79
|
+
mobileReplaceElementValue,
|
|
80
|
+
} from './commands/element';
|
|
81
|
+
import {
|
|
82
|
+
execute,
|
|
83
|
+
executeMobile,
|
|
84
|
+
} from './commands/execute';
|
|
85
|
+
import {
|
|
86
|
+
doFindElementOrEls,
|
|
87
|
+
} from './commands/find';
|
|
88
|
+
import {
|
|
89
|
+
mobileClickGesture,
|
|
90
|
+
mobileDoubleClickGesture,
|
|
91
|
+
mobileDragGesture,
|
|
92
|
+
mobileFlingGesture,
|
|
93
|
+
mobileLongClickGesture,
|
|
94
|
+
mobilePinchCloseGesture,
|
|
95
|
+
mobilePinchOpenGesture,
|
|
96
|
+
mobileScroll,
|
|
97
|
+
mobileScrollBackTo,
|
|
98
|
+
mobileScrollGesture,
|
|
99
|
+
mobileSwipeGesture,
|
|
100
|
+
} from './commands/gestures';
|
|
101
|
+
import {
|
|
102
|
+
pressKeyCode,
|
|
103
|
+
longPressKeyCode,
|
|
104
|
+
mobilePressKey,
|
|
105
|
+
mobileType,
|
|
106
|
+
doSendKeys,
|
|
107
|
+
keyevent,
|
|
108
|
+
} from './commands/keyboard';
|
|
109
|
+
import {
|
|
110
|
+
getPageSource,
|
|
111
|
+
getOrientation,
|
|
112
|
+
setOrientation,
|
|
113
|
+
getClipboard,
|
|
114
|
+
openNotifications,
|
|
115
|
+
suspendChromedriverProxy,
|
|
116
|
+
mobileGetDeviceInfo,
|
|
117
|
+
} from './commands/misc';
|
|
118
|
+
import {
|
|
119
|
+
setUrl,
|
|
120
|
+
mobileDeepLink,
|
|
121
|
+
back,
|
|
122
|
+
} from './commands/navigation';
|
|
123
|
+
import {
|
|
124
|
+
mobileScreenshots,
|
|
125
|
+
mobileViewportScreenshot,
|
|
126
|
+
getScreenshot,
|
|
127
|
+
getViewportScreenshot,
|
|
128
|
+
} from './commands/screenshot';
|
|
129
|
+
import {
|
|
130
|
+
doSwipe,
|
|
131
|
+
doDrag,
|
|
132
|
+
touchDown,
|
|
133
|
+
touchLongClick,
|
|
134
|
+
touchMove,
|
|
135
|
+
touchUp,
|
|
136
|
+
tap,
|
|
137
|
+
doPerformMultiAction,
|
|
138
|
+
performActions,
|
|
139
|
+
releaseActions,
|
|
140
|
+
} from './commands/touch';
|
|
141
|
+
import {
|
|
142
|
+
getStatusBarHeight,
|
|
143
|
+
getDevicePixelRatio,
|
|
144
|
+
getDisplayDensity,
|
|
145
|
+
getViewPortRect,
|
|
146
|
+
getWindowRect,
|
|
147
|
+
getWindowSize,
|
|
148
|
+
mobileViewPortRect,
|
|
149
|
+
} from './commands/viewport';
|
|
43
150
|
|
|
44
151
|
// The range of ports we can use on the system for communicating to the
|
|
45
152
|
// UiAutomator2 HTTP server on the device
|
|
@@ -207,7 +314,6 @@ class AndroidUiautomator2Driver
|
|
|
207
314
|
this.desiredCapConstraints = _.cloneDeep(UIAUTOMATOR2_CONSTRAINTS);
|
|
208
315
|
this.jwpProxyActive = false;
|
|
209
316
|
this.jwpProxyAvoid = NO_PROXY;
|
|
210
|
-
this.apkStrings = {}; // map of language -> strings obj
|
|
211
317
|
this._originalIme = null;
|
|
212
318
|
|
|
213
319
|
this.settings = new DeviceSettings(
|
|
@@ -226,10 +332,7 @@ class AndroidUiautomator2Driver
|
|
|
226
332
|
}
|
|
227
333
|
|
|
228
334
|
override validateDesiredCaps(caps: any): caps is Uiautomator2DriverCaps {
|
|
229
|
-
return (
|
|
230
|
-
BaseDriver.prototype.validateDesiredCaps.call(this, caps) &&
|
|
231
|
-
androidHelpers.validateDesiredCaps(caps)
|
|
232
|
-
);
|
|
335
|
+
return super.validateDesiredCaps(caps);
|
|
233
336
|
}
|
|
234
337
|
|
|
235
338
|
async createSession(
|
|
@@ -271,7 +374,7 @@ class AndroidUiautomator2Driver
|
|
|
271
374
|
|
|
272
375
|
if (this.isChromeSession) {
|
|
273
376
|
this.log.info("We're going to run a Chrome-based session");
|
|
274
|
-
const {pkg, activity} =
|
|
377
|
+
const {pkg, activity} = utils.getChromePkg(this.opts.browserName!);
|
|
275
378
|
this.opts.appPackage = this.caps.appPackage = pkg;
|
|
276
379
|
this.opts.appActivity = this.caps.appActivity = activity;
|
|
277
380
|
this.log.info(`Chrome-type package and activity are ${pkg} and ${activity}`);
|
|
@@ -354,7 +457,7 @@ class AndroidUiautomator2Driver
|
|
|
354
457
|
`Forwarding UiAutomator2 Server port ${DEVICE_PORT} to local port ${localPort}`
|
|
355
458
|
);
|
|
356
459
|
if ((await checkPortStatus(localPort, LOCALHOST_IP4)) === 'open') {
|
|
357
|
-
this.log.errorAndThrow(
|
|
460
|
+
throw this.log.errorAndThrow(
|
|
358
461
|
`UiAutomator2 Server cannot start because the local port #${localPort} is busy. ` +
|
|
359
462
|
`Make sure the port you provide via 'systemPort' capability is not occupied. ` +
|
|
360
463
|
`This situation might often be a result of an inaccurate sessions management, e.g. ` +
|
|
@@ -374,13 +477,12 @@ class AndroidUiautomator2Driver
|
|
|
374
477
|
try {
|
|
375
478
|
this.systemPort = await findAPortNotInUse(startPort, endPort);
|
|
376
479
|
} catch (e) {
|
|
377
|
-
this.log.errorAndThrow(
|
|
480
|
+
throw this.log.errorAndThrow(
|
|
378
481
|
`Cannot find any free port in range ${startPort}..${endPort}}. ` +
|
|
379
482
|
`Please set the available port number by providing the systemPort capability or ` +
|
|
380
483
|
`double check the processes that are locking ports within this range and terminate ` +
|
|
381
484
|
`these which are not needed anymore`
|
|
382
485
|
);
|
|
383
|
-
throw new Error(); // unreachable
|
|
384
486
|
}
|
|
385
487
|
await forwardPort(this.systemPort);
|
|
386
488
|
});
|
|
@@ -422,14 +524,14 @@ class AndroidUiautomator2Driver
|
|
|
422
524
|
caps: Uiautomator2StartSessionOpts
|
|
423
525
|
): Promise<Uiautomator2SessionCaps> {
|
|
424
526
|
// get device udid for this session
|
|
425
|
-
const {udid, emPort} = await
|
|
527
|
+
const {udid, emPort} = await this.getDeviceInfoFromCaps();
|
|
426
528
|
this.opts.udid = udid;
|
|
427
529
|
// @ts-expect-error do not put random stuff on opts
|
|
428
530
|
this.opts.emPort = emPort;
|
|
429
531
|
|
|
430
532
|
// now that we know our java version and device info, we can create our
|
|
431
533
|
// ADB instance
|
|
432
|
-
this.adb = await
|
|
534
|
+
this.adb = await this.createADB();
|
|
433
535
|
|
|
434
536
|
const apiLevel = await this.adb.getApiLevel();
|
|
435
537
|
|
|
@@ -470,7 +572,7 @@ class AndroidUiautomator2Driver
|
|
|
470
572
|
}
|
|
471
573
|
|
|
472
574
|
// get appPackage et al from manifest if necessary
|
|
473
|
-
const appInfo = await
|
|
575
|
+
const appInfo = await this.getLaunchInfo();
|
|
474
576
|
// and get it onto our 'opts' object so we use it from now on
|
|
475
577
|
this.opts = {...this.opts, ...(appInfo ?? {})};
|
|
476
578
|
|
|
@@ -489,7 +591,7 @@ class AndroidUiautomator2Driver
|
|
|
489
591
|
if (this.opts.hideKeyboard) {
|
|
490
592
|
this._originalIme = await this.adb.defaultIME();
|
|
491
593
|
}
|
|
492
|
-
await
|
|
594
|
+
await this.initDevice();
|
|
493
595
|
|
|
494
596
|
// Prepare the device by forwarding the UiAutomator2 port
|
|
495
597
|
// This call mutates this.systemPort if it is not set explicitly
|
|
@@ -544,7 +646,7 @@ class AndroidUiautomator2Driver
|
|
|
544
646
|
// Unlock the device after the session is started.
|
|
545
647
|
if (!this.opts.skipUnlock) {
|
|
546
648
|
// unlock the device to prepare it for testing
|
|
547
|
-
await
|
|
649
|
+
await this.unlock();
|
|
548
650
|
} else {
|
|
549
651
|
this.log.debug(`'skipUnlock' capability set, so skipping device unlock`);
|
|
550
652
|
}
|
|
@@ -623,9 +725,8 @@ class AndroidUiautomator2Driver
|
|
|
623
725
|
async initAUT() {
|
|
624
726
|
// Uninstall any uninstallOtherPackages which were specified in caps
|
|
625
727
|
if (this.opts.uninstallOtherPackages) {
|
|
626
|
-
await
|
|
627
|
-
this.
|
|
628
|
-
helpers.parseArray(this.opts.uninstallOtherPackages),
|
|
728
|
+
await this.uninstallOtherPackages(
|
|
729
|
+
utils.parseArray(this.opts.uninstallOtherPackages),
|
|
629
730
|
[SETTINGS_HELPER_ID, SERVER_PACKAGE_ID, SERVER_TEST_PACKAGE_ID]
|
|
630
731
|
);
|
|
631
732
|
}
|
|
@@ -634,15 +735,14 @@ class AndroidUiautomator2Driver
|
|
|
634
735
|
if (this.opts.otherApps) {
|
|
635
736
|
let otherApps;
|
|
636
737
|
try {
|
|
637
|
-
otherApps =
|
|
738
|
+
otherApps = utils.parseArray(this.opts.otherApps);
|
|
638
739
|
} catch (e) {
|
|
639
|
-
this.log.errorAndThrow(`Could not parse "otherApps" capability: ${(e as Error).message}`);
|
|
640
|
-
throw new Error(); // unrechable
|
|
740
|
+
throw this.log.errorAndThrow(`Could not parse "otherApps" capability: ${(e as Error).message}`);
|
|
641
741
|
}
|
|
642
742
|
otherApps = await B.all(
|
|
643
743
|
otherApps.map((app) => this.helpers.configureApp(app, [APK_EXTENSION, APKS_EXTENSION]))
|
|
644
744
|
);
|
|
645
|
-
await
|
|
745
|
+
await this.installOtherApks(otherApps);
|
|
646
746
|
}
|
|
647
747
|
|
|
648
748
|
if (this.opts.app) {
|
|
@@ -656,12 +756,12 @@ class AndroidUiautomator2Driver
|
|
|
656
756
|
requireDefaultCert: false,
|
|
657
757
|
}))
|
|
658
758
|
) {
|
|
659
|
-
await
|
|
759
|
+
await signApp(this.adb!, this.opts.app);
|
|
660
760
|
}
|
|
661
761
|
if (!this.opts.skipUninstall) {
|
|
662
762
|
await this.adb!.uninstallApk(this.opts.appPackage!);
|
|
663
763
|
}
|
|
664
|
-
await
|
|
764
|
+
await this.installAUT();
|
|
665
765
|
} else {
|
|
666
766
|
this.log.debug(
|
|
667
767
|
'noReset has been requested and the app is already installed. Doing nothing'
|
|
@@ -669,13 +769,13 @@ class AndroidUiautomator2Driver
|
|
|
669
769
|
}
|
|
670
770
|
} else {
|
|
671
771
|
if (this.opts.fullReset) {
|
|
672
|
-
this.log.errorAndThrow(
|
|
772
|
+
throw this.log.errorAndThrow(
|
|
673
773
|
'Full reset requires an app capability, use fastReset if app is not provided'
|
|
674
774
|
);
|
|
675
775
|
}
|
|
676
776
|
this.log.debug('No app capability. Assuming it is already on the device');
|
|
677
777
|
if (this.opts.fastReset && this.opts.appPackage) {
|
|
678
|
-
await
|
|
778
|
+
await this.resetAUT();
|
|
679
779
|
}
|
|
680
780
|
}
|
|
681
781
|
}
|
|
@@ -738,8 +838,6 @@ class AndroidUiautomator2Driver
|
|
|
738
838
|
},
|
|
739
839
|
];
|
|
740
840
|
|
|
741
|
-
await androidHelpers.removeAllSessionWebSocketHandlers(this.server, this.sessionId);
|
|
742
|
-
|
|
743
841
|
try {
|
|
744
842
|
await this.stopChromedriverProxies();
|
|
745
843
|
} catch (err) {
|
|
@@ -827,14 +925,13 @@ class AndroidUiautomator2Driver
|
|
|
827
925
|
this.log.info('Closing MJPEG stream');
|
|
828
926
|
this.mjpegStream.stop();
|
|
829
927
|
}
|
|
830
|
-
await
|
|
928
|
+
await super.deleteSession();
|
|
831
929
|
}
|
|
832
930
|
|
|
833
931
|
async checkAppPresent() {
|
|
834
932
|
this.log.debug('Checking whether app is actually present');
|
|
835
933
|
if (!this.opts.app || !(await fs.exists(this.opts.app))) {
|
|
836
|
-
this.log.errorAndThrow(`Could not find app apk at '${this.opts.app}'`);
|
|
837
|
-
throw new Error(); // unreachable
|
|
934
|
+
throw this.log.errorAndThrow(`Could not find app apk at '${this.opts.app}'`);
|
|
838
935
|
}
|
|
839
936
|
}
|
|
840
937
|
|
|
@@ -887,8 +984,100 @@ class AndroidUiautomator2Driver
|
|
|
887
984
|
)) as Partial<Uiautomator2Settings>;
|
|
888
985
|
return {...driverSettings, ...serverSettings} as any;
|
|
889
986
|
}
|
|
890
|
-
}
|
|
891
987
|
|
|
892
|
-
|
|
988
|
+
mobileGetActionHistory = mobileGetActionHistory;
|
|
989
|
+
mobileScheduleAction = mobileScheduleAction;
|
|
990
|
+
mobileUnscheduleAction = mobileUnscheduleAction;
|
|
991
|
+
|
|
992
|
+
getAlertText = getAlertText;
|
|
993
|
+
mobileAcceptAlert = mobileAcceptAlert;
|
|
994
|
+
mobileDismissAlert = mobileDismissAlert;
|
|
995
|
+
postAcceptAlert = postAcceptAlert;
|
|
996
|
+
postDismissAlert = postDismissAlert;
|
|
997
|
+
|
|
998
|
+
mobileInstallMultipleApks = mobileInstallMultipleApks;
|
|
999
|
+
mobileBackgroundApp = mobileBackgroundApp;
|
|
1000
|
+
|
|
1001
|
+
mobileGetAppStrings = mobileGetAppStrings;
|
|
1002
|
+
|
|
1003
|
+
mobileGetBatteryInfo = mobileGetBatteryInfo;
|
|
1004
|
+
|
|
1005
|
+
active = active;
|
|
1006
|
+
getAttribute = getAttribute;
|
|
1007
|
+
elementEnabled = elementEnabled;
|
|
1008
|
+
elementDisplayed = elementDisplayed;
|
|
1009
|
+
elementSelected = elementSelected;
|
|
1010
|
+
getName = getName;
|
|
1011
|
+
getLocation = getLocation;
|
|
1012
|
+
getSize = getSize;
|
|
1013
|
+
getElementRect = getElementRect;
|
|
1014
|
+
getElementScreenshot = getElementScreenshot;
|
|
1015
|
+
getText = getText;
|
|
1016
|
+
setValueImmediate = setValueImmediate;
|
|
1017
|
+
doSetElementValue = doSetElementValue;
|
|
1018
|
+
click = click;
|
|
1019
|
+
clear = clear;
|
|
1020
|
+
mobileReplaceElementValue = mobileReplaceElementValue;
|
|
1021
|
+
|
|
1022
|
+
execute = execute;
|
|
1023
|
+
executeMobile = executeMobile;
|
|
1024
|
+
|
|
1025
|
+
doFindElementOrEls = doFindElementOrEls;
|
|
1026
|
+
|
|
1027
|
+
mobileClickGesture = mobileClickGesture;
|
|
1028
|
+
mobileDoubleClickGesture = mobileDoubleClickGesture;
|
|
1029
|
+
mobileDragGesture = mobileDragGesture;
|
|
1030
|
+
mobileFlingGesture = mobileFlingGesture;
|
|
1031
|
+
mobileLongClickGesture = mobileLongClickGesture;
|
|
1032
|
+
mobilePinchCloseGesture = mobilePinchCloseGesture;
|
|
1033
|
+
mobilePinchOpenGesture = mobilePinchOpenGesture;
|
|
1034
|
+
mobileScroll = mobileScroll;
|
|
1035
|
+
mobileScrollBackTo = mobileScrollBackTo;
|
|
1036
|
+
mobileScrollGesture = mobileScrollGesture;
|
|
1037
|
+
mobileSwipeGesture = mobileSwipeGesture;
|
|
1038
|
+
|
|
1039
|
+
pressKeyCode = pressKeyCode;
|
|
1040
|
+
longPressKeyCode = longPressKeyCode;
|
|
1041
|
+
mobilePressKey = mobilePressKey;
|
|
1042
|
+
mobileType = mobileType;
|
|
1043
|
+
doSendKeys = doSendKeys;
|
|
1044
|
+
keyevent = keyevent;
|
|
1045
|
+
|
|
1046
|
+
getPageSource = getPageSource;
|
|
1047
|
+
getOrientation = getOrientation;
|
|
1048
|
+
setOrientation = setOrientation;
|
|
1049
|
+
getClipboard = getClipboard;
|
|
1050
|
+
openNotifications = openNotifications;
|
|
1051
|
+
suspendChromedriverProxy = suspendChromedriverProxy;
|
|
1052
|
+
mobileGetDeviceInfo = mobileGetDeviceInfo;
|
|
1053
|
+
|
|
1054
|
+
setUrl = setUrl;
|
|
1055
|
+
mobileDeepLink = mobileDeepLink;
|
|
1056
|
+
back = back;
|
|
1057
|
+
|
|
1058
|
+
mobileScreenshots = mobileScreenshots;
|
|
1059
|
+
mobileViewportScreenshot = mobileViewportScreenshot;
|
|
1060
|
+
getScreenshot = getScreenshot;
|
|
1061
|
+
getViewportScreenshot = getViewportScreenshot;
|
|
1062
|
+
|
|
1063
|
+
doSwipe = doSwipe;
|
|
1064
|
+
doDrag = doDrag;
|
|
1065
|
+
touchDown = touchDown;
|
|
1066
|
+
touchLongClick = touchLongClick;
|
|
1067
|
+
touchMove = touchMove;
|
|
1068
|
+
touchUp = touchUp;
|
|
1069
|
+
tap = tap;
|
|
1070
|
+
doPerformMultiAction = doPerformMultiAction;
|
|
1071
|
+
performActions = performActions;
|
|
1072
|
+
releaseActions = releaseActions;
|
|
1073
|
+
|
|
1074
|
+
getStatusBarHeight = getStatusBarHeight;
|
|
1075
|
+
getDevicePixelRatio = getDevicePixelRatio;
|
|
1076
|
+
getDisplayDensity = getDisplayDensity;
|
|
1077
|
+
getViewPortRect = getViewPortRect;
|
|
1078
|
+
getWindowRect = getWindowRect;
|
|
1079
|
+
getWindowSize = getWindowSize;
|
|
1080
|
+
mobileViewPortRect = mobileViewPortRect;
|
|
1081
|
+
}
|
|
893
1082
|
|
|
894
1083
|
export {AndroidUiautomator2Driver};
|
package/lib/helpers.js
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { fs, system } from 'appium/support';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (has) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
let msg = 'Your apk does not have INTERNET permissions. Uiautomator2 needs ' +
|
|
13
|
-
'the internet permission to proceed. Please check if you have ' +
|
|
14
|
-
'<uses-permission android:name="android.**permission.INTERNET"/>' +
|
|
15
|
-
'in your AndroidManifest.xml';
|
|
16
|
-
throw new Error(msg);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
helpers.isWriteable = async function isWriteable (filePath) {
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} filePath
|
|
6
|
+
* @returns {Promise<boolean>}
|
|
7
|
+
*/
|
|
8
|
+
export async function isWriteable(filePath) {
|
|
20
9
|
try {
|
|
21
10
|
await fs.access(filePath, fs.W_OK);
|
|
22
11
|
if (system.isWindows()) {
|
|
@@ -30,15 +19,19 @@ helpers.isWriteable = async function isWriteable (filePath) {
|
|
|
30
19
|
} catch (ign) {
|
|
31
20
|
return false;
|
|
32
21
|
}
|
|
33
|
-
}
|
|
22
|
+
}
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {import('appium-adb').ADB} adb
|
|
27
|
+
* @param {string} appPath
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
*/
|
|
30
|
+
export async function signApp(adb, appPath) {
|
|
31
|
+
if (!await isWriteable(appPath)) {
|
|
37
32
|
throw new Error(`The application at '${appPath}' is not writeable. ` +
|
|
38
33
|
`Please grant write permissions to this file or to its parent folder '${path.dirname(appPath)}' ` +
|
|
39
34
|
`for the Appium process, so it could sign the application`);
|
|
40
35
|
}
|
|
41
36
|
await adb.sign(appPath);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default helpers;
|
|
37
|
+
}
|
package/lib/uiautomator2.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
util, logger, tempDir, fs, timing
|
|
11
11
|
} from 'appium/support';
|
|
12
12
|
import B from 'bluebird';
|
|
13
|
-
import
|
|
13
|
+
import {isWriteable, signApp} from './helpers';
|
|
14
14
|
import axios from 'axios';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
|
|
@@ -89,7 +89,7 @@ class UiAutomator2Server {
|
|
|
89
89
|
if (await this.adb.checkApkCert(resultInfo.appPath, appId)) {
|
|
90
90
|
resultInfo.wasSigned = true;
|
|
91
91
|
} else {
|
|
92
|
-
if (!await
|
|
92
|
+
if (!await isWriteable(appPath)) {
|
|
93
93
|
this.log.warn(
|
|
94
94
|
`Server package at '${appPath}' is not writeable. ` +
|
|
95
95
|
`Will copy it into the temporary location at '${tmpRoot}' as a workaround. ` +
|
|
@@ -99,7 +99,7 @@ class UiAutomator2Server {
|
|
|
99
99
|
await fs.copyFile(appPath, dstPath);
|
|
100
100
|
resultInfo.appPath = dstPath;
|
|
101
101
|
}
|
|
102
|
-
await
|
|
102
|
+
await signApp(this.adb, resultInfo.appPath);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (appId === SERVER_TEST_PACKAGE_ID && await this.adb.isAppInstalled(appId)) {
|