appium-android-driver 4.49.0 → 4.52.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/build/lib/android-helpers.js +52 -38
- package/build/lib/commands/context.js +4 -1
- package/build/lib/commands/execute.js +3 -2
- package/build/lib/commands/general.js +21 -33
- package/build/lib/commands/performance.js +106 -88
- package/build/lib/desired-caps.js +8 -1
- package/build/lib/unlock-helpers.js +85 -104
- package/build/lib/webview-helpers.js +8 -4
- package/lib/android-helpers.js +53 -34
- package/lib/commands/context.js +3 -0
- package/lib/commands/execute.js +2 -0
- package/lib/commands/general.js +34 -21
- package/lib/commands/performance.js +146 -115
- package/lib/desired-caps.js +7 -0
- package/lib/unlock-helpers.js +99 -96
- package/lib/webview-helpers.js +9 -6
- package/package.json +4 -4
package/lib/unlock-helpers.js
CHANGED
|
@@ -8,85 +8,80 @@ const PIN_UNLOCK_KEY_EVENT = 'pinWithKeyEvent';
|
|
|
8
8
|
const PASSWORD_UNLOCK = 'password';
|
|
9
9
|
const PATTERN_UNLOCK = 'pattern';
|
|
10
10
|
const FINGERPRINT_UNLOCK = 'fingerprint';
|
|
11
|
-
const UNLOCK_TYPES = [
|
|
11
|
+
const UNLOCK_TYPES = [
|
|
12
|
+
PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK,
|
|
13
|
+
PATTERN_UNLOCK, FINGERPRINT_UNLOCK
|
|
14
|
+
];
|
|
12
15
|
const KEYCODE_NUMPAD_ENTER = 66;
|
|
13
|
-
const KEYCODE_POWER = 26;
|
|
14
|
-
const KEYCODE_WAKEUP = 224; // Can work over API Level 20
|
|
15
16
|
const UNLOCK_WAIT_TIME = 100;
|
|
16
|
-
const HIDE_KEYBOARD_WAIT_TIME = 100;
|
|
17
17
|
const INPUT_KEYS_WAIT_TIME = 100;
|
|
18
18
|
const NUMBER_ZERO_KEYCODE = 7;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
helpers.isValidUnlockType = function isValidUnlockType (type) {
|
|
22
|
-
return UNLOCK_TYPES.includes(type);
|
|
23
|
-
};
|
|
20
|
+
const helpers = {};
|
|
24
21
|
|
|
25
|
-
helpers.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
helpers.validateUnlockCapabilities = function validateUnlockCapabilities (caps = {}) {
|
|
23
|
+
const {
|
|
24
|
+
unlockKey,
|
|
25
|
+
unlockType,
|
|
26
|
+
} = caps;
|
|
27
|
+
if (_.isNil(unlockKey) || unlockKey === '') {
|
|
28
|
+
throw new Error('A non-empty unlock key value must be provided');
|
|
31
29
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
|
|
31
|
+
if ([PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, FINGERPRINT_UNLOCK].includes(unlockType)) {
|
|
32
|
+
if (!/^[0-9]+$/.test(_.trim(unlockKey))) {
|
|
33
|
+
throw new Error(`Unlock key value '${unlockKey}' must only consist of digits`);
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
} else if (unlockType === PATTERN_UNLOCK) {
|
|
36
|
+
if (!/^[1-9]{2,9}$/.test(_.trim(unlockKey))) {
|
|
37
|
+
throw new Error(`Unlock key value '${unlockKey}' must only include from two to nine digits in range 1..9`);
|
|
38
|
+
}
|
|
39
|
+
if (/([1-9]).*?\1/.test(_.trim(unlockKey))) {
|
|
40
|
+
throw new Error(`Unlock key value '${unlockKey}' must define a valid pattern where repeats are not allowed`);
|
|
41
|
+
}
|
|
42
|
+
} else if (unlockType === PASSWORD_UNLOCK) {
|
|
43
|
+
// Dont trim password key, you can use blank spaces in your android password
|
|
44
|
+
// ¯\_(ツ)_/¯
|
|
45
|
+
if (!/.{4,}/g.test(unlockKey)) {
|
|
46
|
+
throw new Error(`The minimum allowed length of unlock key value '${unlockKey}' is 4 characters`);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error(`Invalid unlock type '${unlockType}'. ` +
|
|
50
|
+
`Only the following unlock types are supported: ${UNLOCK_TYPES}`);
|
|
42
51
|
}
|
|
43
|
-
|
|
52
|
+
return caps;
|
|
44
53
|
};
|
|
45
54
|
|
|
46
|
-
helpers.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
await
|
|
55
|
-
//
|
|
56
|
-
|
|
55
|
+
helpers.fastUnlock = async function fastUnlock (adb, opts = {}) {
|
|
56
|
+
const {
|
|
57
|
+
credential,
|
|
58
|
+
credentialType,
|
|
59
|
+
} = opts;
|
|
60
|
+
logger.info(`Unlocking the device via ADB using ${credentialType} credential '${credential}'`);
|
|
61
|
+
const wasLockEnabled = await adb.isLockEnabled();
|
|
62
|
+
if (wasLockEnabled) {
|
|
63
|
+
await adb.clearLockCredential(credential);
|
|
64
|
+
// not sure why, but the device's screen still remains locked
|
|
65
|
+
// if a preliminary wake up cycle has not been performed
|
|
66
|
+
await adb.cycleWakeUp();
|
|
67
|
+
} else {
|
|
68
|
+
logger.info('No active lock has been detected. Proceeding to the keyguard dismissal');
|
|
57
69
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
await adb.shell(['wm', 'dismiss-keyguard']);
|
|
65
|
-
return;
|
|
70
|
+
try {
|
|
71
|
+
await adb.dismissKeyguard();
|
|
72
|
+
} finally {
|
|
73
|
+
if (wasLockEnabled) {
|
|
74
|
+
await adb.setLockCredential(credentialType, credential);
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
|
-
logger.info('Swiping up to dismiss keyguard');
|
|
68
|
-
await helpers.swipeUp(driver);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
helpers.swipeUp = async function swipeUp (driver) {
|
|
72
|
-
let windowSize = await driver.getWindowSize();
|
|
73
|
-
let x0 = parseInt(windowSize.x / 2, 10);
|
|
74
|
-
let y0 = windowSize.y - 10;
|
|
75
|
-
let yP = 100;
|
|
76
|
-
let actions = [
|
|
77
|
-
{action: 'press', options: {element: null, x: x0, y: y0}},
|
|
78
|
-
{action: 'moveTo', options: {element: null, x: x0, y: yP}},
|
|
79
|
-
{action: 'release'}
|
|
80
|
-
];
|
|
81
|
-
await driver.performTouch(actions);
|
|
82
77
|
};
|
|
83
78
|
|
|
84
79
|
helpers.encodePassword = function encodePassword (key) {
|
|
85
|
-
return key
|
|
80
|
+
return `${key}`.replace(/\s/ig, '%s');
|
|
86
81
|
};
|
|
87
82
|
|
|
88
83
|
helpers.stringKeyToArr = function stringKeyToArr (key) {
|
|
89
|
-
return key
|
|
84
|
+
return `${key}`.trim().replace(/\s+/g, '').split(/\s*/);
|
|
90
85
|
};
|
|
91
86
|
|
|
92
87
|
helpers.fingerprintUnlock = async function fingerprintUnlock (adb, driver, capabilities) {
|
|
@@ -99,26 +94,26 @@ helpers.fingerprintUnlock = async function fingerprintUnlock (adb, driver, capab
|
|
|
99
94
|
|
|
100
95
|
helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
|
|
101
96
|
logger.info(`Trying to unlock device using pin ${capabilities.unlockKey}`);
|
|
102
|
-
await
|
|
103
|
-
|
|
97
|
+
await adb.dismissKeyguard();
|
|
98
|
+
const keys = helpers.stringKeyToArr(capabilities.unlockKey);
|
|
104
99
|
if (await adb.getApiLevel() >= 21) {
|
|
105
|
-
|
|
100
|
+
const els = await driver.findElOrEls('id', 'com.android.systemui:id/digit_text', true);
|
|
106
101
|
if (_.isEmpty(els)) {
|
|
107
102
|
// fallback to pin with key event
|
|
108
103
|
return await helpers.pinUnlockWithKeyEvent(adb, driver, capabilities);
|
|
109
104
|
}
|
|
110
|
-
|
|
111
|
-
for (
|
|
112
|
-
|
|
105
|
+
const pins = {};
|
|
106
|
+
for (const el of els) {
|
|
107
|
+
const text = await driver.getAttribute('text', util.unwrapElement(el));
|
|
113
108
|
pins[text] = el;
|
|
114
109
|
}
|
|
115
|
-
for (
|
|
116
|
-
|
|
110
|
+
for (const pin of keys) {
|
|
111
|
+
const el = pins[pin];
|
|
117
112
|
await driver.click(util.unwrapElement(el));
|
|
118
113
|
}
|
|
119
114
|
} else {
|
|
120
|
-
for (
|
|
121
|
-
|
|
115
|
+
for (const pin of keys) {
|
|
116
|
+
const el = await driver.findElOrEls('id', `com.android.keyguard:id/key${pin}`, false);
|
|
122
117
|
if (el === null) {
|
|
123
118
|
// fallback to pin with key event
|
|
124
119
|
return await helpers.pinUnlockWithKeyEvent(adb, driver, capabilities);
|
|
@@ -126,10 +121,9 @@ helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
|
|
|
126
121
|
await driver.click(util.unwrapElement(el));
|
|
127
122
|
}
|
|
128
123
|
}
|
|
129
|
-
await waitForUnlock(adb
|
|
124
|
+
await waitForUnlock(adb);
|
|
130
125
|
};
|
|
131
126
|
|
|
132
|
-
|
|
133
127
|
/**
|
|
134
128
|
* Wait for the display to be unlocked.
|
|
135
129
|
* Some devices automatically accept typed 'pin' and 'password' code
|
|
@@ -139,21 +133,20 @@ helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
|
|
|
139
133
|
* the enter key code.
|
|
140
134
|
*
|
|
141
135
|
* @param {ADB} adb The instance of ADB
|
|
142
|
-
* @param {AndroidDriver} driver The instance of AndroidDriver
|
|
143
136
|
*/
|
|
144
|
-
async function waitForUnlock (adb
|
|
137
|
+
async function waitForUnlock (adb) {
|
|
145
138
|
await sleep(UNLOCK_WAIT_TIME);
|
|
146
139
|
if (!await adb.isScreenLocked()) {
|
|
147
140
|
return;
|
|
148
141
|
}
|
|
149
142
|
|
|
150
|
-
await
|
|
143
|
+
await adb.keyevent(KEYCODE_NUMPAD_ENTER);
|
|
151
144
|
await sleep(UNLOCK_WAIT_TIME);
|
|
152
145
|
}
|
|
153
146
|
|
|
154
147
|
helpers.pinUnlockWithKeyEvent = async function pinUnlockWithKeyEvent (adb, driver, capabilities) {
|
|
155
148
|
logger.info(`Trying to unlock device using pin with keycode ${capabilities.unlockKey}`);
|
|
156
|
-
await
|
|
149
|
+
await adb.dismissKeyguard();
|
|
157
150
|
const keys = helpers.stringKeyToArr(capabilities.unlockKey);
|
|
158
151
|
|
|
159
152
|
// Some device does not have system key ids like 'com.android.keyguard:id/key'
|
|
@@ -167,11 +160,11 @@ helpers.pinUnlockWithKeyEvent = async function pinUnlockWithKeyEvent (adb, drive
|
|
|
167
160
|
};
|
|
168
161
|
|
|
169
162
|
helpers.passwordUnlock = async function passwordUnlock (adb, driver, capabilities) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
163
|
+
const { unlockKey } = capabilities;
|
|
164
|
+
logger.info(`Trying to unlock device using password ${unlockKey}`);
|
|
165
|
+
await adb.dismissKeyguard();
|
|
173
166
|
// Replace blank spaces with %s
|
|
174
|
-
key = helpers.encodePassword(
|
|
167
|
+
const key = helpers.encodePassword(unlockKey);
|
|
175
168
|
// Why adb ? It was less flaky
|
|
176
169
|
await adb.shell(['input', 'text', key]);
|
|
177
170
|
// Why sleeps ? Avoid some flakyness waiting for the input to receive the keys
|
|
@@ -192,21 +185,24 @@ helpers.getPatternKeyPosition = function getPatternKeyPosition (key, initPos, pi
|
|
|
192
185
|
const pins = 9;
|
|
193
186
|
const xPos = (key, x, piece) => Math.round(x + ((key % cols) || cols) * piece - piece / 2);
|
|
194
187
|
const yPos = (key, y, piece) => Math.round(y + (Math.ceil(((key % pins) || pins) / cols) * piece - piece / 2));
|
|
195
|
-
return {
|
|
188
|
+
return {
|
|
189
|
+
x: xPos(key, initPos.x, piece),
|
|
190
|
+
y: yPos(key, initPos.y, piece)
|
|
191
|
+
};
|
|
196
192
|
};
|
|
197
193
|
|
|
198
194
|
helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
|
|
199
|
-
|
|
195
|
+
const actions = [];
|
|
200
196
|
let lastPos;
|
|
201
197
|
for (let key of keys) {
|
|
202
|
-
|
|
198
|
+
const keyPos = helpers.getPatternKeyPosition(key, initPos, piece);
|
|
203
199
|
if (key === keys[0]) {
|
|
204
200
|
actions.push({action: 'press', options: {element: null, x: keyPos.x, y: keyPos.y}});
|
|
205
201
|
lastPos = keyPos;
|
|
206
202
|
continue;
|
|
207
203
|
}
|
|
208
|
-
|
|
209
|
-
|
|
204
|
+
const moveTo = {x: 0, y: 0};
|
|
205
|
+
const diffX = keyPos.x - lastPos.x;
|
|
210
206
|
if (diffX > 0) {
|
|
211
207
|
moveTo.x = piece;
|
|
212
208
|
if (Math.abs(diffX) > piece) {
|
|
@@ -218,7 +214,7 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
|
|
|
218
214
|
moveTo.x -= piece;
|
|
219
215
|
}
|
|
220
216
|
}
|
|
221
|
-
|
|
217
|
+
const diffY = keyPos.y - lastPos.y;
|
|
222
218
|
if (diffY > 0) {
|
|
223
219
|
moveTo.y = piece;
|
|
224
220
|
if (Math.abs(diffY) > piece) {
|
|
@@ -230,7 +226,10 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
|
|
|
230
226
|
moveTo.y -= piece;
|
|
231
227
|
}
|
|
232
228
|
}
|
|
233
|
-
actions.push({
|
|
229
|
+
actions.push({
|
|
230
|
+
action: 'moveTo',
|
|
231
|
+
options: {element: null, x: moveTo.x + lastPos.x, y: moveTo.y + lastPos.y}
|
|
232
|
+
});
|
|
234
233
|
lastPos = keyPos;
|
|
235
234
|
}
|
|
236
235
|
actions.push({action: 'release'});
|
|
@@ -238,9 +237,10 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
|
|
|
238
237
|
};
|
|
239
238
|
|
|
240
239
|
helpers.patternUnlock = async function patternUnlock (adb, driver, capabilities) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
const { unlockKey } = capabilities;
|
|
241
|
+
logger.info(`Trying to unlock device using pattern ${unlockKey}`);
|
|
242
|
+
await adb.dismissKeyguard();
|
|
243
|
+
const keys = helpers.stringKeyToArr(unlockKey);
|
|
244
244
|
/* We set the device pattern buttons as number of a regular phone
|
|
245
245
|
* | • • • | | 1 2 3 |
|
|
246
246
|
* | • • • | --> | 4 5 6 |
|
|
@@ -250,15 +250,15 @@ helpers.patternUnlock = async function patternUnlock (adb, driver, capabilities)
|
|
|
250
250
|
included inside a FrameLayout, so we are going to try clicking on the buttons
|
|
251
251
|
using the parent view bounds and math.
|
|
252
252
|
*/
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
const apiLevel = await adb.getApiLevel();
|
|
254
|
+
const el = await driver.findElOrEls('id',
|
|
255
255
|
`com.android.${apiLevel >= 21 ? 'systemui' : 'keyguard'}:id/lockPatternView`,
|
|
256
256
|
false
|
|
257
257
|
);
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
const initPos = await driver.getLocation(util.unwrapElement(el));
|
|
259
|
+
const size = await driver.getSize(util.unwrapElement(el));
|
|
260
260
|
// Get actions to perform
|
|
261
|
-
|
|
261
|
+
const actions = helpers.getPatternActions(keys, initPos, size.width / 3);
|
|
262
262
|
// Perform gesture
|
|
263
263
|
await driver.performTouch(actions);
|
|
264
264
|
// Waits a bit for the device to be unlocked
|
|
@@ -271,5 +271,8 @@ helpers.PASSWORD_UNLOCK = PASSWORD_UNLOCK;
|
|
|
271
271
|
helpers.PATTERN_UNLOCK = PATTERN_UNLOCK;
|
|
272
272
|
helpers.FINGERPRINT_UNLOCK = FINGERPRINT_UNLOCK;
|
|
273
273
|
|
|
274
|
-
export {
|
|
274
|
+
export {
|
|
275
|
+
PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK, PATTERN_UNLOCK,
|
|
276
|
+
FINGERPRINT_UNLOCK, helpers
|
|
277
|
+
};
|
|
275
278
|
export default helpers;
|
package/lib/webview-helpers.js
CHANGED
|
@@ -517,17 +517,20 @@ helpers.createChromedriverCaps = function createChromedriverCaps (opts, deviceId
|
|
|
517
517
|
// add device id from adb
|
|
518
518
|
caps.chromeOptions.androidDeviceSerial = deviceId;
|
|
519
519
|
|
|
520
|
-
if (opts.loggingPrefs) {
|
|
521
|
-
|
|
520
|
+
if (_.isPlainObject(opts.loggingPrefs) || _.isPlainObject(opts.chromeLoggingPrefs)) {
|
|
521
|
+
if (opts.loggingPrefs) {
|
|
522
|
+
logger.warn(`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`);
|
|
523
|
+
}
|
|
524
|
+
caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
|
|
522
525
|
}
|
|
523
526
|
if (opts.enablePerformanceLogging) {
|
|
524
527
|
logger.warn(`The 'enablePerformanceLogging' cap is deprecated; simply use ` +
|
|
525
|
-
`the '
|
|
528
|
+
`the 'chromeLoggingPrefs' cap instead, with a 'performance' key set to 'ALL'`);
|
|
526
529
|
const newPref = {performance: 'ALL'};
|
|
527
530
|
// don't overwrite other logging prefs that have been sent in if they exist
|
|
528
|
-
caps.loggingPrefs = caps.loggingPrefs
|
|
529
|
-
Object.assign({}, caps.loggingPrefs, newPref)
|
|
530
|
-
newPref;
|
|
531
|
+
caps.loggingPrefs = caps.loggingPrefs
|
|
532
|
+
? Object.assign({}, caps.loggingPrefs, newPref)
|
|
533
|
+
: newPref;
|
|
531
534
|
}
|
|
532
535
|
|
|
533
536
|
if (opts.chromeOptions?.Arguments) {
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"mobile",
|
|
10
10
|
"mobile testing"
|
|
11
11
|
],
|
|
12
|
-
"version": "4.
|
|
12
|
+
"version": "4.52.1",
|
|
13
13
|
"author": "appium",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
15
|
"repository": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@babel/runtime": "^7.0.0",
|
|
39
|
-
"appium-adb": "^8.
|
|
39
|
+
"appium-adb": "^8.16.0",
|
|
40
40
|
"appium-base-driver": "^7.0.0",
|
|
41
41
|
"appium-chromedriver": "^4.13.0",
|
|
42
42
|
"appium-support": "^2.47.1",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"precommit-test"
|
|
78
78
|
],
|
|
79
79
|
"devDependencies": {
|
|
80
|
+
"@xmldom/xmldom": "^0.x",
|
|
80
81
|
"android-apidemos": "^3.0.0",
|
|
81
82
|
"appium-gulp-plugins": "^5.4.0",
|
|
82
83
|
"appium-test-support": "^1.0.0",
|
|
@@ -87,8 +88,7 @@
|
|
|
87
88
|
"mocha": "^9.0.0",
|
|
88
89
|
"mock-fs": "^5.0.0",
|
|
89
90
|
"pre-commit": "^1.1.3",
|
|
90
|
-
"sinon": "^
|
|
91
|
-
"xmldom": "^0.x",
|
|
91
|
+
"sinon": "^12.0.0",
|
|
92
92
|
"xpath": "^0.x"
|
|
93
93
|
}
|
|
94
94
|
}
|