appium-uiautomator2-driver 1.71.0 → 1.75.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/README.md +25 -5
- package/build/lib/commands/find.js +5 -11
- package/build/lib/commands/general.js +4 -2
- package/build/lib/css-converter.js +119 -112
- package/build/lib/driver.js +4 -3
- package/build/lib/uiautomator2.js +2 -1
- package/lib/commands/find.js +5 -9
- package/lib/commands/general.js +3 -0
- package/lib/css-converter.js +177 -169
- package/lib/driver.js +16 -4
- package/lib/uiautomator2.js +1 -0
- package/package.json +9 -9
package/lib/commands/general.js
CHANGED
|
@@ -170,6 +170,8 @@ extensions.executeMobile = async function (mobileCommand, opts = {}) {
|
|
|
170
170
|
installMultipleApks: 'mobileInstallMultipleApks',
|
|
171
171
|
|
|
172
172
|
unlock: 'mobileUnlock',
|
|
173
|
+
|
|
174
|
+
refreshGpsCache: 'mobileRefreshGpsCache',
|
|
173
175
|
};
|
|
174
176
|
|
|
175
177
|
if (!_.has(mobileCommandsMapping, mobileCommand)) {
|
|
@@ -277,6 +279,7 @@ helpers.wrapBootstrapDisconnect = async function (wrapped) {
|
|
|
277
279
|
helpers.suspendChromedriverProxy = function () {
|
|
278
280
|
this.chromedriver = null;
|
|
279
281
|
this.proxyReqRes = this.uiautomator2.proxyReqRes.bind(this.uiautomator2);
|
|
282
|
+
this.proxyCommand = this.uiautomator2.proxyCommand.bind(this.uiautomator2);
|
|
280
283
|
this.jwpProxyActive = true;
|
|
281
284
|
};
|
|
282
285
|
|
package/lib/css-converter.js
CHANGED
|
@@ -2,8 +2,6 @@ import { CssSelectorParser } from 'css-selector-parser';
|
|
|
2
2
|
import { escapeRegExp } from 'lodash';
|
|
3
3
|
import { errors } from 'appium-base-driver';
|
|
4
4
|
|
|
5
|
-
const CssConverter = {};
|
|
6
|
-
|
|
7
5
|
const parser = new CssSelectorParser();
|
|
8
6
|
parser.registerSelectorPseudos('has');
|
|
9
7
|
parser.registerNestingOperators('>', '+', '~');
|
|
@@ -113,16 +111,6 @@ function getWordMatcherRegex (word) {
|
|
|
113
111
|
return `\\b(\\w*${escapeRegExp(word)}\\w*)\\b`;
|
|
114
112
|
}
|
|
115
113
|
|
|
116
|
-
/**
|
|
117
|
-
* Add android:id/ to beginning of string if it's not there already
|
|
118
|
-
*
|
|
119
|
-
* @param {string} locator The initial locator
|
|
120
|
-
* @returns {string} String with `android:id/` prepended (if it wasn't already)
|
|
121
|
-
*/
|
|
122
|
-
function formatIdLocator (locator) {
|
|
123
|
-
return ID_LOCATOR_PATTERN.test(locator) ? locator : `android:id/${locator}`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
114
|
/**
|
|
127
115
|
* @typedef {Object} CssAttr
|
|
128
116
|
* @property {?string} valueType Type of attribute (must be string or empty)
|
|
@@ -131,62 +119,20 @@ function formatIdLocator (locator) {
|
|
|
131
119
|
*/
|
|
132
120
|
|
|
133
121
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* @
|
|
137
|
-
* @
|
|
122
|
+
* @typedef {Object} CssRule
|
|
123
|
+
* @property {?string} nestingOperator The nesting operator (aka: combinator https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors)
|
|
124
|
+
* @property {?string} tagName The tag name (aka: type selector https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors)
|
|
125
|
+
* @property {?string[]} classNames An array of CSS class names
|
|
126
|
+
* @property {?CssAttr[]} attrs An array of CSS attributes
|
|
127
|
+
* @property {?CssPseudo[]} attrs An array of CSS pseudos
|
|
128
|
+
* @property {?string} id CSS identifier
|
|
129
|
+
* @property {?CssRule} rule A descendant of this CSS rule
|
|
138
130
|
*/
|
|
139
|
-
function parseAttr (cssAttr) {
|
|
140
|
-
if (cssAttr.valueType && cssAttr.valueType !== 'string') {
|
|
141
|
-
throw new Error(`'${cssAttr.name}=${cssAttr.value}' is an invalid attribute. ` +
|
|
142
|
-
`Only 'string' and empty attribute types are supported. Found '${cssAttr.valueType}'`);
|
|
143
|
-
}
|
|
144
|
-
const attrName = assertGetAttrName(cssAttr);
|
|
145
|
-
const methodName = toSnakeCase(attrName);
|
|
146
|
-
|
|
147
|
-
// Validate that it's a supported attribute
|
|
148
|
-
if (!STR_ATTRS.includes(attrName) && !BOOLEAN_ATTRS.includes(attrName)) {
|
|
149
|
-
throw new Error(`'${attrName}' is not supported. Supported attributes are ` +
|
|
150
|
-
`'${[...STR_ATTRS, ...BOOLEAN_ATTRS].join(', ')}'`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Parse boolean, if it's a boolean attribute
|
|
154
|
-
if (BOOLEAN_ATTRS.includes(attrName)) {
|
|
155
|
-
return `.${methodName}(${assertGetBool(cssAttr)})`;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Otherwise parse as string
|
|
159
|
-
let value = cssAttr.value || '';
|
|
160
|
-
if (attrName === RESOURCE_ID) {
|
|
161
|
-
value = formatIdLocator(value);
|
|
162
|
-
}
|
|
163
|
-
if (value === '') {
|
|
164
|
-
return `.${methodName}Matches("")`;
|
|
165
|
-
}
|
|
166
131
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (['description', 'text'].includes(attrName)) {
|
|
172
|
-
return `.${methodName}Contains("${value}")`;
|
|
173
|
-
}
|
|
174
|
-
return `.${methodName}Matches("${escapeRegExp(value)}")`;
|
|
175
|
-
case '^=':
|
|
176
|
-
if (['description', 'text'].includes(attrName)) {
|
|
177
|
-
return `.${methodName}StartsWith("${value}")`;
|
|
178
|
-
}
|
|
179
|
-
return `.${methodName}Matches("^${escapeRegExp(value)}")`;
|
|
180
|
-
case '$=':
|
|
181
|
-
return `.${methodName}Matches("${escapeRegExp(value)}$")`;
|
|
182
|
-
case '~=':
|
|
183
|
-
return `.${methodName}Matches("${getWordMatcherRegex(value)}")`;
|
|
184
|
-
default:
|
|
185
|
-
// Unreachable, but adding error in case a new CSS attribute is added.
|
|
186
|
-
throw new Error(`Unsupported CSS attribute operator '${cssAttr.operator}'. ` +
|
|
187
|
-
` '=', '*=', '^=', '$=' and '~=' are supported.`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
132
|
+
/**
|
|
133
|
+
* @typedef {Object} CssObject
|
|
134
|
+
* @property {?string} type Type of CSS object. 'rule', 'ruleset' or 'selectors'
|
|
135
|
+
*/
|
|
190
136
|
|
|
191
137
|
/**
|
|
192
138
|
* @typedef {Object} CssPseudo
|
|
@@ -195,126 +141,188 @@ function parseAttr (cssAttr) {
|
|
|
195
141
|
* @property {?string} value The value of the pseudo selector
|
|
196
142
|
*/
|
|
197
143
|
|
|
198
|
-
|
|
199
|
-
* Convert a CSS pseudo class to a UiSelector
|
|
200
|
-
*
|
|
201
|
-
* @param {CssPseudo} cssPseudo CSS Pseudo class
|
|
202
|
-
* @returns {string} Pseudo selector parsed as UiSelector
|
|
203
|
-
*/
|
|
204
|
-
function parsePseudo (cssPseudo) {
|
|
205
|
-
if (cssPseudo.valueType && cssPseudo.valueType !== 'string') {
|
|
206
|
-
throw new Error(`'${cssPseudo.name}=${cssPseudo.value}'. ` +
|
|
207
|
-
`Unsupported css pseudo class value type: '${cssPseudo.valueType}'. Only 'string' type or empty is supported.`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const pseudoName = assertGetAttrName(cssPseudo);
|
|
144
|
+
class CssConverter {
|
|
211
145
|
|
|
212
|
-
|
|
213
|
-
|
|
146
|
+
constructor (selector, pkg) {
|
|
147
|
+
this.selector = selector;
|
|
148
|
+
this.pkg = pkg;
|
|
214
149
|
}
|
|
215
150
|
|
|
216
|
-
|
|
217
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Add `<pkgName>:id/` prefix to beginning of string if it's not there already
|
|
153
|
+
*
|
|
154
|
+
* @param {string} locator The initial locator
|
|
155
|
+
* @returns {string} String with `<pkgName>:id/` prepended (if it wasn't already)
|
|
156
|
+
*/
|
|
157
|
+
formatIdLocator (locator) {
|
|
158
|
+
return ID_LOCATOR_PATTERN.test(locator)
|
|
159
|
+
? locator
|
|
160
|
+
: `${this.pkg || 'android'}:id/${locator}`;
|
|
218
161
|
}
|
|
219
|
-
}
|
|
220
162
|
|
|
221
|
-
/**
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Convert a CSS attribute into a UiSelector method call
|
|
165
|
+
*
|
|
166
|
+
* @param {CssAttr} cssAttr CSS attribute object
|
|
167
|
+
* @returns {string} CSS attribute parsed as UiSelector
|
|
168
|
+
*/
|
|
169
|
+
parseAttr (cssAttr) {
|
|
170
|
+
if (cssAttr.valueType && cssAttr.valueType !== 'string') {
|
|
171
|
+
throw new Error(`'${cssAttr.name}=${cssAttr.value}' is an invalid attribute. ` +
|
|
172
|
+
`Only 'string' and empty attribute types are supported. Found '${cssAttr.valueType}'`);
|
|
173
|
+
}
|
|
174
|
+
const attrName = assertGetAttrName(cssAttr);
|
|
175
|
+
const methodName = toSnakeCase(attrName);
|
|
231
176
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const { nestingOperator } = cssRule;
|
|
238
|
-
if (nestingOperator && nestingOperator !== ' ') {
|
|
239
|
-
throw new Error(`'${nestingOperator}' is not a supported combinator. ` +
|
|
240
|
-
`Only child combinator (>) and descendant combinator are supported.`);
|
|
241
|
-
}
|
|
177
|
+
// Validate that it's a supported attribute
|
|
178
|
+
if (!STR_ATTRS.includes(attrName) && !BOOLEAN_ATTRS.includes(attrName)) {
|
|
179
|
+
throw new Error(`'${attrName}' is not supported. Supported attributes are ` +
|
|
180
|
+
`'${[...STR_ATTRS, ...BOOLEAN_ATTRS].join(', ')}'`);
|
|
181
|
+
}
|
|
242
182
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (cssRule.classNames) {
|
|
247
|
-
for (const cssClassNames of cssRule.classNames) {
|
|
248
|
-
androidClass.push(cssClassNames);
|
|
249
|
-
}
|
|
250
|
-
uiAutomatorSelector += `.className("${androidClass.join('.')}")`;
|
|
251
|
-
} else {
|
|
252
|
-
uiAutomatorSelector += `.classNameMatches("${cssRule.tagName}")`;
|
|
183
|
+
// Parse boolean, if it's a boolean attribute
|
|
184
|
+
if (BOOLEAN_ATTRS.includes(attrName)) {
|
|
185
|
+
return `.${methodName}(${assertGetBool(cssAttr)})`;
|
|
253
186
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
if (cssRule.attrs) {
|
|
261
|
-
for (const attr of cssRule.attrs) {
|
|
262
|
-
uiAutomatorSelector += parseAttr(attr);
|
|
187
|
+
|
|
188
|
+
// Otherwise parse as string
|
|
189
|
+
let value = cssAttr.value || '';
|
|
190
|
+
if (attrName === RESOURCE_ID) {
|
|
191
|
+
value = this.formatIdLocator(value);
|
|
263
192
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
193
|
+
if (value === '') {
|
|
194
|
+
return `.${methodName}Matches("")`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
switch (cssAttr.operator) {
|
|
198
|
+
case '=':
|
|
199
|
+
return `.${methodName}("${value}")`;
|
|
200
|
+
case '*=':
|
|
201
|
+
if (['description', 'text'].includes(attrName)) {
|
|
202
|
+
return `.${methodName}Contains("${value}")`;
|
|
203
|
+
}
|
|
204
|
+
return `.${methodName}Matches("${escapeRegExp(value)}")`;
|
|
205
|
+
case '^=':
|
|
206
|
+
if (['description', 'text'].includes(attrName)) {
|
|
207
|
+
return `.${methodName}StartsWith("${value}")`;
|
|
208
|
+
}
|
|
209
|
+
return `.${methodName}Matches("^${escapeRegExp(value)}")`;
|
|
210
|
+
case '$=':
|
|
211
|
+
return `.${methodName}Matches("${escapeRegExp(value)}$")`;
|
|
212
|
+
case '~=':
|
|
213
|
+
return `.${methodName}Matches("${getWordMatcherRegex(value)}")`;
|
|
214
|
+
default:
|
|
215
|
+
// Unreachable, but adding error in case a new CSS attribute is added.
|
|
216
|
+
throw new Error(`Unsupported CSS attribute operator '${cssAttr.operator}'. ` +
|
|
217
|
+
` '=', '*=', '^=', '$=' and '~=' are supported.`);
|
|
268
218
|
}
|
|
269
219
|
}
|
|
270
|
-
|
|
271
|
-
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Convert a CSS pseudo class to a UiSelector
|
|
223
|
+
*
|
|
224
|
+
* @param {CssPseudo} cssPseudo CSS Pseudo class
|
|
225
|
+
* @returns {string} Pseudo selector parsed as UiSelector
|
|
226
|
+
*/
|
|
227
|
+
parsePseudo (cssPseudo) {
|
|
228
|
+
if (cssPseudo.valueType && cssPseudo.valueType !== 'string') {
|
|
229
|
+
throw new Error(`'${cssPseudo.name}=${cssPseudo.value}'. ` +
|
|
230
|
+
`Unsupported css pseudo class value type: '${cssPseudo.valueType}'. Only 'string' type or empty is supported.`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const pseudoName = assertGetAttrName(cssPseudo);
|
|
234
|
+
|
|
235
|
+
if (BOOLEAN_ATTRS.includes(pseudoName)) {
|
|
236
|
+
return `.${toSnakeCase(pseudoName)}(${assertGetBool(cssPseudo)})`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (NUMERIC_ATTRS.includes(pseudoName)) {
|
|
240
|
+
return `.${pseudoName}(${cssPseudo.value})`;
|
|
241
|
+
}
|
|
272
242
|
}
|
|
273
|
-
return uiAutomatorSelector;
|
|
274
|
-
}
|
|
275
243
|
|
|
276
|
-
/**
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Convert a CSS rule to a UiSelector
|
|
246
|
+
* @param {CssRule} cssRule CSS rule definition
|
|
247
|
+
*/
|
|
248
|
+
parseCssRule (cssRule) {
|
|
249
|
+
const { nestingOperator } = cssRule;
|
|
250
|
+
if (nestingOperator && nestingOperator !== ' ') {
|
|
251
|
+
throw new Error(`'${nestingOperator}' is not a supported combinator. ` +
|
|
252
|
+
`Only child combinator (>) and descendant combinator are supported.`);
|
|
253
|
+
}
|
|
280
254
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
255
|
+
let uiAutomatorSelector = 'new UiSelector()';
|
|
256
|
+
if (cssRule.tagName && cssRule.tagName !== '*') {
|
|
257
|
+
let androidClass = [cssRule.tagName];
|
|
258
|
+
if (cssRule.classNames) {
|
|
259
|
+
for (const cssClassNames of cssRule.classNames) {
|
|
260
|
+
androidClass.push(cssClassNames);
|
|
261
|
+
}
|
|
262
|
+
uiAutomatorSelector += `.className("${androidClass.join('.')}")`;
|
|
263
|
+
} else {
|
|
264
|
+
uiAutomatorSelector += `.classNameMatches("${cssRule.tagName}")`;
|
|
265
|
+
}
|
|
266
|
+
} else if (cssRule.classNames) {
|
|
267
|
+
uiAutomatorSelector += `.classNameMatches("${cssRule.classNames.join('\\.')}")`;
|
|
268
|
+
}
|
|
269
|
+
if (cssRule.id) {
|
|
270
|
+
uiAutomatorSelector += `.resourceId("${this.formatIdLocator(cssRule.id)}")`;
|
|
271
|
+
}
|
|
272
|
+
if (cssRule.attrs) {
|
|
273
|
+
for (const attr of cssRule.attrs) {
|
|
274
|
+
uiAutomatorSelector += this.parseAttr(attr);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (cssRule.pseudos) {
|
|
278
|
+
for (const pseudo of cssRule.pseudos) {
|
|
279
|
+
uiAutomatorSelector += this.parsePseudo(pseudo);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (cssRule.rule) {
|
|
283
|
+
uiAutomatorSelector += `.childSelector(${this.parseCssRule(cssRule.rule)})`;
|
|
284
|
+
}
|
|
285
|
+
return uiAutomatorSelector;
|
|
298
286
|
}
|
|
299
|
-
}
|
|
300
287
|
|
|
301
|
-
/**
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Convert CSS object to UiAutomator2 selector
|
|
290
|
+
* @param {CssObject} css CSS object
|
|
291
|
+
* @returns {string} The CSS object parsed as a UiSelector
|
|
292
|
+
*/
|
|
293
|
+
parseCssObject (css) {
|
|
294
|
+
switch (css.type) {
|
|
295
|
+
case 'rule':
|
|
296
|
+
return this.parseCssRule(css);
|
|
297
|
+
case 'ruleSet':
|
|
298
|
+
return this.parseCssObject(css.rule);
|
|
299
|
+
case 'selectors':
|
|
300
|
+
return css.selectors.map((selector) => this.parseCssObject(selector)).join('; ');
|
|
301
|
+
|
|
302
|
+
default:
|
|
303
|
+
// This is never reachable, but if it ever is do this.
|
|
304
|
+
throw new Error(`UiAutomator does not support '${css.type}' css. Only supports 'rule', 'ruleSet', 'selectors' `);
|
|
305
|
+
}
|
|
312
306
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Convert a CSS selector to a UiAutomator2 selector
|
|
310
|
+
*
|
|
311
|
+
* @returns {string} The CSS selector converted to a UiSelector
|
|
312
|
+
*/
|
|
313
|
+
toUiAutomatorSelector () {
|
|
314
|
+
let cssObj;
|
|
315
|
+
try {
|
|
316
|
+
cssObj = parser.parse(this.selector);
|
|
317
|
+
} catch (e) {
|
|
318
|
+
throw new errors.InvalidSelectorError(`Invalid CSS selector '${this.selector}'. Reason: '${e}'`);
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
return this.parseCssObject(cssObj);
|
|
322
|
+
} catch (e) {
|
|
323
|
+
throw new errors.InvalidSelectorError(`Unsupported CSS selector '${this.selector}'. Reason: '${e}'`);
|
|
324
|
+
}
|
|
317
325
|
}
|
|
318
|
-
}
|
|
326
|
+
}
|
|
319
327
|
|
|
320
328
|
export default CssConverter;
|
package/lib/driver.js
CHANGED
|
@@ -67,7 +67,6 @@ const NO_PROXY = [
|
|
|
67
67
|
['GET', new RegExp('^/session/[^/]+/element/[^/]+/selected')],
|
|
68
68
|
['GET', new RegExp('^/session/[^/]+/ime/[^/]+')],
|
|
69
69
|
['GET', new RegExp('^/session/[^/]+/location')],
|
|
70
|
-
['GET', new RegExp('^/session/[^/]+/log/types')],
|
|
71
70
|
['GET', new RegExp('^/session/[^/]+/network_connection')],
|
|
72
71
|
['GET', new RegExp('^/session/[^/]+/screenshot')],
|
|
73
72
|
['GET', new RegExp('^/session/[^/]+/timeouts')],
|
|
@@ -94,7 +93,6 @@ const NO_PROXY = [
|
|
|
94
93
|
['POST', new RegExp('^/session/[^/]+/ime/[^/]+')],
|
|
95
94
|
['POST', new RegExp('^/session/[^/]+/keys')],
|
|
96
95
|
['POST', new RegExp('^/session/[^/]+/location')],
|
|
97
|
-
['POST', new RegExp('^/session/[^/]+/log')],
|
|
98
96
|
['POST', new RegExp('^/session/[^/]+/network_connection')],
|
|
99
97
|
['POST', new RegExp('^/session/[^/]+/timeouts')],
|
|
100
98
|
['POST', new RegExp('^/session/[^/]+/touch/multi/perform')],
|
|
@@ -102,12 +100,18 @@ const NO_PROXY = [
|
|
|
102
100
|
['POST', new RegExp('^/session/[^/]+/url')],
|
|
103
101
|
|
|
104
102
|
// MJSONWP commands
|
|
103
|
+
['GET', new RegExp('^/session/[^/]+/log/types')],
|
|
105
104
|
['POST', new RegExp('^/session/[^/]+/execute')],
|
|
106
105
|
['POST', new RegExp('^/session/[^/]+/execute_async')],
|
|
106
|
+
['POST', new RegExp('^/session/[^/]+/log')],
|
|
107
107
|
// W3C commands
|
|
108
|
+
// For Selenium v4 (W3C does not have this route)
|
|
109
|
+
['GET', new RegExp('^/session/[^/]+/se/log/types')],
|
|
108
110
|
['GET', new RegExp('^/session/[^/]+/window/rect')],
|
|
109
111
|
['POST', new RegExp('^/session/[^/]+/execute/async')],
|
|
110
112
|
['POST', new RegExp('^/session/[^/]+/execute/sync')],
|
|
113
|
+
// For Selenium v4 (W3C does not have this route)
|
|
114
|
+
['POST', new RegExp('^/session/[^/]+/se/log')],
|
|
111
115
|
];
|
|
112
116
|
|
|
113
117
|
// This is a set of methods and paths that we never want to proxy to Chromedriver.
|
|
@@ -115,11 +119,9 @@ const CHROME_NO_PROXY = [
|
|
|
115
119
|
['GET', new RegExp('^/session/[^/]+/appium')],
|
|
116
120
|
['GET', new RegExp('^/session/[^/]+/context')],
|
|
117
121
|
['GET', new RegExp('^/session/[^/]+/element/[^/]+/rect')],
|
|
118
|
-
['GET', new RegExp('^/session/[^/]+/log/types$')],
|
|
119
122
|
['GET', new RegExp('^/session/[^/]+/orientation')],
|
|
120
123
|
['POST', new RegExp('^/session/[^/]+/appium')],
|
|
121
124
|
['POST', new RegExp('^/session/[^/]+/context')],
|
|
122
|
-
['POST', new RegExp('^/session/[^/]+/log$')],
|
|
123
125
|
['POST', new RegExp('^/session/[^/]+/orientation')],
|
|
124
126
|
['POST', new RegExp('^/session/[^/]+/touch/multi/perform')],
|
|
125
127
|
['POST', new RegExp('^/session/[^/]+/touch/perform')],
|
|
@@ -127,6 +129,15 @@ const CHROME_NO_PROXY = [
|
|
|
127
129
|
// this is needed to make the mobile: commands working in web context
|
|
128
130
|
['POST', new RegExp('^/session/[^/]+/execute$')],
|
|
129
131
|
['POST', new RegExp('^/session/[^/]+/execute/sync')],
|
|
132
|
+
|
|
133
|
+
// MJSONWP commands
|
|
134
|
+
['GET', new RegExp('^/session/[^/]+/log/types$')],
|
|
135
|
+
['POST', new RegExp('^/session/[^/]+/log$')],
|
|
136
|
+
// W3C commands
|
|
137
|
+
// For Selenium v4 (W3C does not have this route)
|
|
138
|
+
['GET', new RegExp('^/session/[^/]+/se/log/types$')],
|
|
139
|
+
// For Selenium v4 (W3C does not have this route)
|
|
140
|
+
['POST', new RegExp('^/session/[^/]+/se/log$')],
|
|
130
141
|
];
|
|
131
142
|
|
|
132
143
|
const MEMOIZED_FUNCTIONS = [
|
|
@@ -487,6 +498,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
|
|
|
487
498
|
// uiautomator2 with the appropriate options
|
|
488
499
|
this.uiautomator2 = new UiAutomator2Server(uiautomator2Opts);
|
|
489
500
|
this.proxyReqRes = this.uiautomator2.proxyReqRes.bind(this.uiautomator2);
|
|
501
|
+
this.proxyCommand = this.uiautomator2.proxyCommand.bind(this.uiautomator2);
|
|
490
502
|
|
|
491
503
|
if (this.opts.skipServerInstallation) {
|
|
492
504
|
logger.info(`'skipServerInstallation' is set. Skipping UIAutomator2 server installation.`);
|
package/lib/uiautomator2.js
CHANGED
|
@@ -55,6 +55,7 @@ class UiAutomator2Server {
|
|
|
55
55
|
}
|
|
56
56
|
this.jwproxy = new UIA2Proxy(proxyOpts);
|
|
57
57
|
this.proxyReqRes = this.jwproxy.proxyReqRes.bind(this.jwproxy);
|
|
58
|
+
this.proxyCommand = this.jwproxy.command.bind(this.jwproxy);
|
|
58
59
|
this.jwproxy.didInstrumentationExit = false;
|
|
59
60
|
}
|
|
60
61
|
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"automated testing",
|
|
8
8
|
"android"
|
|
9
9
|
],
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.75.0",
|
|
11
11
|
"author": "appium",
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"repository": {
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@babel/runtime": "^7.0.0",
|
|
44
|
-
"appium-adb": "^8.
|
|
45
|
-
"appium-android-driver": "^4.
|
|
44
|
+
"appium-adb": "^8.18.0",
|
|
45
|
+
"appium-android-driver": "^4.54.0",
|
|
46
46
|
"appium-base-driver": "^7.0.0",
|
|
47
47
|
"appium-chromedriver": "^4.23.1",
|
|
48
|
-
"appium-support": "^2.
|
|
49
|
-
"appium-uiautomator2-server": "^4.
|
|
48
|
+
"appium-support": "^2.54.4",
|
|
49
|
+
"appium-uiautomator2-server": "^4.29.0",
|
|
50
50
|
"asyncbox": "^2.3.1",
|
|
51
51
|
"axios": "^0.x",
|
|
52
52
|
"bluebird": "^3.5.1",
|
|
53
53
|
"css-selector-parser": "^1.4.1",
|
|
54
54
|
"lodash": "^4.17.4",
|
|
55
|
-
"portscanner": "2.2.0",
|
|
56
|
-
"source-map-support": "^0.
|
|
55
|
+
"portscanner": "^2.2.0",
|
|
56
|
+
"source-map-support": "^0.x",
|
|
57
57
|
"teen_process": "^1.3.1"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"test"
|
|
82
82
|
],
|
|
83
83
|
"devDependencies": {
|
|
84
|
+
"@xmldom/xmldom": "^0.x",
|
|
84
85
|
"android-apidemos": "^3.0.0",
|
|
85
86
|
"appium-gulp-plugins": "^5.4.0",
|
|
86
87
|
"appium-test-support": "^1.0.0",
|
|
@@ -95,10 +96,9 @@
|
|
|
95
96
|
"pngjs": "^6.0.0",
|
|
96
97
|
"pre-commit": "^1.2.2",
|
|
97
98
|
"rimraf": "^3.0.0",
|
|
98
|
-
"sinon": "^
|
|
99
|
+
"sinon": "^12.0.0",
|
|
99
100
|
"unzipper": "^0.10.0",
|
|
100
101
|
"wd": "^1.10.3",
|
|
101
|
-
"xmldom": "^0.x",
|
|
102
102
|
"xpath": "^0.x"
|
|
103
103
|
}
|
|
104
104
|
}
|