appium-xcuitest-driver 10.10.0 → 10.11.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/build/lib/app-infos-cache.d.ts +29 -31
- package/build/lib/app-infos-cache.d.ts.map +1 -1
- package/build/lib/app-infos-cache.js +29 -33
- package/build/lib/app-infos-cache.js.map +1 -1
- package/build/lib/app-utils.d.ts +30 -59
- package/build/lib/app-utils.d.ts.map +1 -1
- package/build/lib/app-utils.js +158 -211
- package/build/lib/app-utils.js.map +1 -1
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +4 -8
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +1 -5
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/condition.js +4 -4
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/content-size.js +1 -1
- package/build/lib/commands/content-size.js.map +1 -1
- package/build/lib/commands/find.js +2 -2
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/increase-contrast.js +1 -1
- package/build/lib/commands/increase-contrast.js.map +1 -1
- package/build/lib/commands/keychains.d.ts.map +1 -1
- package/build/lib/commands/keychains.js +1 -5
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +1 -5
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +10 -8
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/permissions.js +1 -1
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/css-converter.d.ts +3 -9
- package/build/lib/css-converter.d.ts.map +1 -1
- package/build/lib/css-converter.js +41 -52
- package/build/lib/css-converter.js.map +1 -1
- package/build/lib/device/real-device-management.js +14 -14
- package/build/lib/device/real-device-management.js.map +1 -1
- package/build/lib/device/simulator-management.d.ts.map +1 -1
- package/build/lib/device/simulator-management.js +8 -4
- package/build/lib/device/simulator-management.js.map +1 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +3 -3
- package/build/lib/driver.js.map +1 -1
- package/build/lib/logger.d.ts +1 -2
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +2 -2
- package/build/lib/logger.js.map +1 -1
- package/build/lib/utils.d.ts +76 -134
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +80 -141
- package/build/lib/utils.js.map +1 -1
- package/lib/{app-infos-cache.js → app-infos-cache.ts} +44 -46
- package/lib/{app-utils.js → app-utils.ts} +215 -245
- package/lib/commands/battery.js +3 -4
- package/lib/commands/biometric.js +1 -2
- package/lib/commands/condition.js +1 -1
- package/lib/commands/content-size.js +1 -1
- package/lib/commands/find.js +1 -1
- package/lib/commands/increase-contrast.js +1 -1
- package/lib/commands/keychains.js +1 -2
- package/lib/commands/localization.js +1 -2
- package/lib/commands/pasteboard.js +9 -8
- package/lib/commands/permissions.js +1 -1
- package/lib/{css-converter.js → css-converter.ts} +75 -88
- package/lib/device/real-device-management.ts +1 -1
- package/lib/device/simulator-management.ts +9 -4
- package/lib/driver.ts +6 -4
- package/lib/logger.ts +3 -0
- package/lib/{utils.js → utils.ts} +102 -139
- package/npm-shrinkwrap.json +38 -32
- package/package.json +3 -3
- package/lib/logger.js +0 -5
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
3
2
|
|
|
4
|
-
const assertSimulator =
|
|
3
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Biometric enrollment');
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Enrolls biometric authentication on a simulated device.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {INSTRUMENT_CHANNEL, services} from 'appium-ios-device';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import { isIos18OrNewer } from '../utils
|
|
3
|
+
import { isIos18OrNewer } from '../utils';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Get all available ConditionInducer configuration information, which can be used with
|
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
3
3
|
import { errors } from 'appium/driver';
|
|
4
4
|
|
|
5
|
-
const assertSimulator =
|
|
5
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Content size ui command');
|
|
6
6
|
|
|
7
7
|
const CONTENT_SIZE = [
|
|
8
8
|
'extra-small',
|
package/lib/commands/find.js
CHANGED
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
3
3
|
import { errors } from 'appium/driver';
|
|
4
4
|
|
|
5
|
-
const assertSimulator =
|
|
5
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Content size ui command');
|
|
6
6
|
|
|
7
7
|
const INCREASE_CONTRAST_CONFIG = [
|
|
8
8
|
'enabled',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
3
2
|
|
|
4
|
-
const assertSimulator =
|
|
3
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Keychain modification');
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Clears keychains on a simulated device.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
3
2
|
|
|
4
|
-
const assertSimulator =
|
|
3
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Localization configuration');
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Change localization settings on the currently booted simulator
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { assertSimulator } from '../utils';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Sets the Simulator's pasteboard content to the given value.
|
|
3
6
|
*
|
|
@@ -9,10 +12,8 @@
|
|
|
9
12
|
* @this {XCUITestDriver}
|
|
10
13
|
*/
|
|
11
14
|
export async function mobileSetPasteboard(content, encoding = 'utf8') {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
if (!content) {
|
|
15
|
+
assertSimulator.call(this, 'Setting pasteboard content');
|
|
16
|
+
if (!_.isString(content)) {
|
|
16
17
|
// can be empty string
|
|
17
18
|
throw new Error('Pasteboard content is mandatory to set');
|
|
18
19
|
}
|
|
@@ -31,10 +32,10 @@ export async function mobileSetPasteboard(content, encoding = 'utf8') {
|
|
|
31
32
|
* @returns {Promise<string>} The pasteboard content string
|
|
32
33
|
*/
|
|
33
34
|
export async function mobileGetPasteboard(encoding = 'utf8') {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
assertSimulator.call(this, 'Getting pasteboard content');
|
|
36
|
+
return await /** @type {import('appium-ios-simulator').Simulator} */ (this.device).simctl.getPasteboard(
|
|
37
|
+
/** @type {BufferEncoding} */ (encoding)
|
|
38
|
+
);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import {PermissionService} from './enum';
|
|
3
3
|
import {assertSimulator as _assertSimulator} from '../utils';
|
|
4
4
|
|
|
5
|
-
const assertSimulator =
|
|
5
|
+
const assertSimulator = (driver) => _assertSimulator.call(driver, 'Permission-related operations');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Resets the given permission for the active application under test.
|
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
import {createParser} from 'css-selector-parser';
|
|
2
2
|
import _ from 'lodash';
|
|
3
3
|
import {errors} from 'appium/driver';
|
|
4
|
-
import log from './logger
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {log} from './logger';
|
|
5
|
+
import type {
|
|
6
|
+
AstAttribute,
|
|
7
|
+
AstPseudoClass,
|
|
8
|
+
AstRule,
|
|
9
|
+
AstSelector,
|
|
10
|
+
AstClassName,
|
|
11
|
+
AstTagName,
|
|
12
|
+
AstId,
|
|
13
|
+
} from 'css-selector-parser';
|
|
14
|
+
|
|
15
|
+
export const CssConverter = {
|
|
16
|
+
toIosClassChainSelector(cssSelector: string): string {
|
|
17
|
+
let cssObj: AstSelector;
|
|
18
|
+
try {
|
|
19
|
+
cssObj = parseCssSelector(cssSelector);
|
|
20
|
+
} catch (e: any) {
|
|
21
|
+
log.debug(e.stack);
|
|
22
|
+
throw new errors.InvalidSelectorError(
|
|
23
|
+
`Invalid CSS selector '${cssSelector}'. Reason: '${e.message}'`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
return parseCssObject(cssObj);
|
|
28
|
+
} catch (e: any) {
|
|
29
|
+
log.debug(e.stack);
|
|
30
|
+
throw new errors.InvalidSelectorError(
|
|
31
|
+
`Unsupported CSS selector '${cssSelector}'. Reason: '${e.message}'`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
7
36
|
|
|
8
37
|
const parseCssSelector = createParser({
|
|
9
38
|
syntax: {
|
|
@@ -26,18 +55,15 @@ const parseCssSelector = createParser({
|
|
|
26
55
|
substitutes: true,
|
|
27
56
|
});
|
|
28
57
|
|
|
29
|
-
const BOOLEAN_ATTRS = ['visible', 'accessible', 'accessibility-container', 'enabled'];
|
|
58
|
+
const BOOLEAN_ATTRS = ['visible', 'accessible', 'accessibility-container', 'enabled'] as const;
|
|
30
59
|
|
|
31
|
-
const NUMERIC_ATTRS = ['index'];
|
|
60
|
+
const NUMERIC_ATTRS = ['index'] as const;
|
|
32
61
|
|
|
33
|
-
const STR_ATTRS = ['label', 'name', 'value', 'type'];
|
|
62
|
+
const STR_ATTRS = ['label', 'name', 'value', 'type'] as const;
|
|
34
63
|
|
|
35
64
|
const ALL_ATTRS = [...BOOLEAN_ATTRS, ...NUMERIC_ATTRS, ...STR_ATTRS];
|
|
36
65
|
|
|
37
|
-
|
|
38
|
-
* @type {[string, string[]][]}
|
|
39
|
-
*/
|
|
40
|
-
const ATTRIBUTE_ALIASES = [
|
|
66
|
+
const ATTRIBUTE_ALIASES: [string, string[]][] = [
|
|
41
67
|
['name', ['id']],
|
|
42
68
|
['index', ['nth-child']],
|
|
43
69
|
];
|
|
@@ -45,10 +71,10 @@ const ATTRIBUTE_ALIASES = [
|
|
|
45
71
|
/**
|
|
46
72
|
* Convert hyphen separated word to camel case
|
|
47
73
|
*
|
|
48
|
-
* @param
|
|
49
|
-
* @returns
|
|
74
|
+
* @param str
|
|
75
|
+
* @returns The hyphen separated word translated to camel case
|
|
50
76
|
*/
|
|
51
|
-
function toCamelCase(str) {
|
|
77
|
+
function toCamelCase(str: string | null | undefined): string {
|
|
52
78
|
if (!str) {
|
|
53
79
|
return '';
|
|
54
80
|
}
|
|
@@ -62,12 +88,11 @@ function toCamelCase(str) {
|
|
|
62
88
|
/**
|
|
63
89
|
* Get the boolean from a CSS object. If empty, return true. If not true/false/empty, throw exception
|
|
64
90
|
*
|
|
65
|
-
* @param
|
|
66
|
-
* @returns
|
|
91
|
+
* @param cssAttr
|
|
92
|
+
* @returns Either 'true' or 'false'. If value is empty, return 'true'
|
|
67
93
|
*/
|
|
68
|
-
function requireBoolean(cssAttr) {
|
|
69
|
-
|
|
70
|
-
const attrValue = cssAttr.value?.value;
|
|
94
|
+
function requireBoolean(cssAttr: AstAttribute | AstPseudoClass): string {
|
|
95
|
+
const attrValue = (cssAttr as any).value?.value;
|
|
71
96
|
const val = _.toLower(attrValue) || 'true'; // an omitted boolean attribute means 'true' (e.g.: input[checked] means checked is true)
|
|
72
97
|
switch (val) {
|
|
73
98
|
case '0':
|
|
@@ -89,14 +114,14 @@ function requireBoolean(cssAttr) {
|
|
|
89
114
|
* Converts to lowercase and if an attribute name is an alias for something else, return
|
|
90
115
|
* what it is an alias for
|
|
91
116
|
*
|
|
92
|
-
* @param
|
|
93
|
-
* @returns
|
|
117
|
+
* @param cssEntity
|
|
118
|
+
* @returns The canonical attribute name
|
|
94
119
|
*/
|
|
95
|
-
function requireEntityName(cssEntity) {
|
|
120
|
+
function requireEntityName(cssEntity: AstAttribute | AstPseudoClass): string {
|
|
96
121
|
const entityName = cssEntity.name.toLowerCase();
|
|
97
122
|
|
|
98
123
|
// Check if it's supported and if it is, return it
|
|
99
|
-
if (ALL_ATTRS.includes(entityName)) {
|
|
124
|
+
if (ALL_ATTRS.includes(entityName as any)) {
|
|
100
125
|
return entityName.toLowerCase();
|
|
101
126
|
}
|
|
102
127
|
|
|
@@ -115,12 +140,11 @@ function requireEntityName(cssEntity) {
|
|
|
115
140
|
/**
|
|
116
141
|
* Convert a CSS attribute into a UiSelector method call
|
|
117
142
|
*
|
|
118
|
-
* @param
|
|
119
|
-
* @returns
|
|
143
|
+
* @param cssAttr CSS attribute object
|
|
144
|
+
* @returns CSS attribute parsed as UiSelector
|
|
120
145
|
*/
|
|
121
|
-
function parseAttr(cssAttr) {
|
|
122
|
-
|
|
123
|
-
const attrValue = cssAttr.value?.value;
|
|
146
|
+
function parseAttr(cssAttr: AstAttribute): string | {index: string | undefined} {
|
|
147
|
+
const attrValue = (cssAttr as any).value?.value;
|
|
124
148
|
if (!_.isString(attrValue) && !_.isEmpty(attrValue)) {
|
|
125
149
|
throw new TypeError(
|
|
126
150
|
`'${cssAttr.name}=${attrValue}' is an invalid attribute. ` +
|
|
@@ -130,7 +154,7 @@ function parseAttr(cssAttr) {
|
|
|
130
154
|
const attrName = toCamelCase(requireEntityName(cssAttr));
|
|
131
155
|
|
|
132
156
|
// Validate that it's a supported attribute
|
|
133
|
-
if (!STR_ATTRS.includes(attrName) && !BOOLEAN_ATTRS.includes(attrName)) {
|
|
157
|
+
if (!STR_ATTRS.includes(attrName as any) && !BOOLEAN_ATTRS.includes(attrName as any)) {
|
|
134
158
|
throw new Error(
|
|
135
159
|
`'${attrName}' is not supported. Supported attributes are ` +
|
|
136
160
|
`'${[...STR_ATTRS, ...BOOLEAN_ATTRS].join(', ')}'`,
|
|
@@ -141,11 +165,11 @@ function parseAttr(cssAttr) {
|
|
|
141
165
|
if (attrName === 'index') {
|
|
142
166
|
return {index: attrValue};
|
|
143
167
|
}
|
|
144
|
-
if (BOOLEAN_ATTRS.includes(attrName)) {
|
|
168
|
+
if (BOOLEAN_ATTRS.includes(attrName as any)) {
|
|
145
169
|
return `${attrName} == ${requireBoolean(cssAttr)}`;
|
|
146
170
|
}
|
|
147
171
|
|
|
148
|
-
|
|
172
|
+
const value = attrValue || '';
|
|
149
173
|
if (value === '') {
|
|
150
174
|
return `[${attrName} LIKE ${value}]`;
|
|
151
175
|
}
|
|
@@ -173,12 +197,11 @@ function parseAttr(cssAttr) {
|
|
|
173
197
|
/**
|
|
174
198
|
* Convert a CSS pseudo class to a UiSelector
|
|
175
199
|
*
|
|
176
|
-
* @param
|
|
177
|
-
* @returns
|
|
200
|
+
* @param cssPseudo
|
|
201
|
+
* @returns Pseudo selector parsed as UiSelector
|
|
178
202
|
*/
|
|
179
|
-
function parsePseudo(cssPseudo) {
|
|
180
|
-
|
|
181
|
-
const argValue = cssPseudo.argument?.value;
|
|
203
|
+
function parsePseudo(cssPseudo: AstPseudoClass): string | {index: string | undefined} | undefined {
|
|
204
|
+
const argValue = (cssPseudo as any).argument?.value;
|
|
182
205
|
if (!_.isString(argValue) && !_.isEmpty(argValue)) {
|
|
183
206
|
throw new TypeError(
|
|
184
207
|
`'${cssPseudo.name}=${argValue}'. ` +
|
|
@@ -188,7 +211,7 @@ function parsePseudo(cssPseudo) {
|
|
|
188
211
|
|
|
189
212
|
const pseudoName = requireEntityName(cssPseudo);
|
|
190
213
|
|
|
191
|
-
if (BOOLEAN_ATTRS.includes(pseudoName)) {
|
|
214
|
+
if (BOOLEAN_ATTRS.includes(pseudoName as any)) {
|
|
192
215
|
return `${toCamelCase(pseudoName)} == ${requireBoolean(cssPseudo)}`;
|
|
193
216
|
}
|
|
194
217
|
|
|
@@ -199,9 +222,9 @@ function parsePseudo(cssPseudo) {
|
|
|
199
222
|
|
|
200
223
|
/**
|
|
201
224
|
* Convert a CSS rule to a UiSelector
|
|
202
|
-
* @param
|
|
225
|
+
* @param cssRule CSS rule definition
|
|
203
226
|
*/
|
|
204
|
-
function parseCssRule(cssRule) {
|
|
227
|
+
function parseCssRule(cssRule: AstRule): string {
|
|
205
228
|
if (cssRule.combinator && ![' ', '>'].includes(cssRule.combinator)) {
|
|
206
229
|
throw new Error(
|
|
207
230
|
`'${cssRule.combinator}' is not a supported combinator. ` +
|
|
@@ -210,9 +233,7 @@ function parseCssRule(cssRule) {
|
|
|
210
233
|
}
|
|
211
234
|
|
|
212
235
|
let iosClassChainSelector = '';
|
|
213
|
-
const astClassNames =
|
|
214
|
-
cssRule.items.filter(({type}) => type === 'ClassName')
|
|
215
|
-
);
|
|
236
|
+
const astClassNames = cssRule.items.filter(({type}) => type === 'ClassName') as AstClassName[];
|
|
216
237
|
const classNames = astClassNames.map(({name}) => name);
|
|
217
238
|
if (classNames.length) {
|
|
218
239
|
throw new errors.InvalidSelectorError(`'${[cssRule || '', ...classNames].join('.')}'
|
|
@@ -220,9 +241,7 @@ function parseCssRule(cssRule) {
|
|
|
220
241
|
dots separating them`);
|
|
221
242
|
}
|
|
222
243
|
|
|
223
|
-
const astTag =
|
|
224
|
-
cssRule.items.find(({type}) => type === 'TagName')
|
|
225
|
-
);
|
|
244
|
+
const astTag = cssRule.items.find(({type}) => type === 'TagName') as AstTagName | undefined;
|
|
226
245
|
let tagName = astTag?.name ?? '';
|
|
227
246
|
if (tagName && tagName !== '*' && !_.startsWith(_.toLower(tagName), 'xcuielementtype')) {
|
|
228
247
|
const capitalizedTagName = tagName.charAt(0).toUpperCase() + tagName.slice(1);
|
|
@@ -230,36 +249,31 @@ function parseCssRule(cssRule) {
|
|
|
230
249
|
}
|
|
231
250
|
iosClassChainSelector += tagName || '*';
|
|
232
251
|
|
|
233
|
-
|
|
234
|
-
const attrs = [];
|
|
252
|
+
const attrs: (string | {index: string | undefined} | undefined)[] = [];
|
|
235
253
|
|
|
236
|
-
const astIds =
|
|
237
|
-
cssRule.items.filter(({type}) => type === 'Id')
|
|
238
|
-
);
|
|
254
|
+
const astIds = cssRule.items.filter(({type}) => type === 'Id') as AstId[];
|
|
239
255
|
const ids = astIds.map(({name}) => name);
|
|
240
256
|
if (ids.length) {
|
|
241
257
|
attrs.push(`name == "${ids[0]}"`);
|
|
242
258
|
}
|
|
243
|
-
const attributes =
|
|
244
|
-
cssRule.items.filter(({type}) => type === 'Attribute')
|
|
245
|
-
);
|
|
259
|
+
const attributes = cssRule.items.filter(({type}) => type === 'Attribute') as AstAttribute[];
|
|
246
260
|
for (const attr of attributes) {
|
|
247
261
|
attrs.push(parseAttr(attr));
|
|
248
262
|
}
|
|
249
|
-
const pseudoClasses =
|
|
250
|
-
cssRule.items.filter(({type}) => type === 'PseudoClass')
|
|
251
|
-
);
|
|
263
|
+
const pseudoClasses = cssRule.items.filter(({type}) => type === 'PseudoClass') as AstPseudoClass[];
|
|
252
264
|
for (const pseudo of pseudoClasses) {
|
|
253
265
|
attrs.push(parsePseudo(pseudo));
|
|
254
266
|
}
|
|
255
|
-
const nonIndexAttrs = attrs.filter((attr) => _.isString(attr));
|
|
267
|
+
const nonIndexAttrs = attrs.filter((attr) => _.isString(attr)) as string[];
|
|
256
268
|
if (!_.isEmpty(nonIndexAttrs)) {
|
|
257
269
|
iosClassChainSelector += `[\`${nonIndexAttrs.join(' AND ')}\`]`;
|
|
258
270
|
}
|
|
259
271
|
|
|
260
|
-
const indexAttr = attrs.find(
|
|
272
|
+
const indexAttr = attrs.find(
|
|
273
|
+
(attr) => _.isObject(attr) && (attr as {index: string}).index
|
|
274
|
+
) as {index: string} | undefined;
|
|
261
275
|
if (indexAttr) {
|
|
262
|
-
iosClassChainSelector += `[${
|
|
276
|
+
iosClassChainSelector += `[${indexAttr.index}]`;
|
|
263
277
|
}
|
|
264
278
|
|
|
265
279
|
if (cssRule.nestedRule) {
|
|
@@ -272,40 +286,13 @@ function parseCssRule(cssRule) {
|
|
|
272
286
|
/**
|
|
273
287
|
* Convert CSS object to iOS Class Chain selector
|
|
274
288
|
*
|
|
275
|
-
* @param
|
|
276
|
-
* @returns
|
|
289
|
+
* @param css CSS object
|
|
290
|
+
* @returns The CSS object parsed as a UiSelector
|
|
277
291
|
*/
|
|
278
|
-
function parseCssObject(css) {
|
|
292
|
+
function parseCssObject(css: AstSelector): string {
|
|
279
293
|
if (!_.isEmpty(css.rules)) {
|
|
280
294
|
return parseCssRule(css.rules[0]);
|
|
281
295
|
}
|
|
282
296
|
|
|
283
297
|
throw new Error('No rules could be parsed out of the current selector');
|
|
284
298
|
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Convert a CSS selector to a iOS Class Chain selector
|
|
288
|
-
* @param {string} cssSelector CSS Selector
|
|
289
|
-
* @returns {string} The CSS selector converted to an iOS Class Chain
|
|
290
|
-
*/
|
|
291
|
-
CssConverter.toIosClassChainSelector = function toIosClassChainSelector(cssSelector) {
|
|
292
|
-
let cssObj;
|
|
293
|
-
try {
|
|
294
|
-
cssObj = parseCssSelector(cssSelector);
|
|
295
|
-
} catch (e) {
|
|
296
|
-
log.debug(e.stack);
|
|
297
|
-
throw new errors.InvalidSelectorError(
|
|
298
|
-
`Invalid CSS selector '${cssSelector}'. Reason: '${e.message}'`,
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
try {
|
|
302
|
-
return parseCssObject(cssObj);
|
|
303
|
-
} catch (e) {
|
|
304
|
-
log.debug(e.stack);
|
|
305
|
-
throw new errors.InvalidSelectorError(
|
|
306
|
-
`Unsupported CSS selector '${cssSelector}'. Reason: '${e.message}'`,
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
export default CssConverter;
|
|
@@ -4,7 +4,7 @@ import {fs, tempDir, mkdirp, zip, util, timing} from 'appium/support';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import {services, utilities, INSTRUMENT_CHANNEL} from 'appium-ios-device';
|
|
6
6
|
import {buildSafariPreferences, SAFARI_BUNDLE_ID} from '../app-utils';
|
|
7
|
-
import defaultLogger from '../logger';
|
|
7
|
+
import {log as defaultLogger} from '../logger';
|
|
8
8
|
import { Devicectl } from 'node-devicectl';
|
|
9
9
|
import type { AppiumLogger } from '@appium/types';
|
|
10
10
|
import type { XCUITestDriver } from '../driver';
|
|
@@ -6,6 +6,7 @@ import {util, timing} from 'appium/support';
|
|
|
6
6
|
import {UDID_AUTO, normalizePlatformName} from '../utils';
|
|
7
7
|
import {buildSafariPreferences} from '../app-utils';
|
|
8
8
|
import type { XCUITestDriver } from '../driver';
|
|
9
|
+
import type { DeviceInfo } from 'node-simctl';
|
|
9
10
|
|
|
10
11
|
const APPIUM_SIM_PREFIX = 'appiumTest';
|
|
11
12
|
|
|
@@ -19,11 +20,15 @@ export async function createSim(this: XCUITestDriver): Promise<Simulator> {
|
|
|
19
20
|
const platform = normalizePlatformName(this.opts.platformName);
|
|
20
21
|
const simctl = new Simctl({devicesSetPath});
|
|
21
22
|
if (!deviceName) {
|
|
22
|
-
let deviceNames: string
|
|
23
|
+
let deviceNames: string[] = [];
|
|
23
24
|
try {
|
|
24
|
-
|
|
25
|
-
.getDevices(platformVersion, platform)
|
|
26
|
-
.
|
|
25
|
+
const devices = platformVersion
|
|
26
|
+
? await simctl.getDevices(platformVersion, platform)
|
|
27
|
+
: await simctl.getDevices(null, platform);
|
|
28
|
+
const nameMapper = (device: DeviceInfo) => device.name;
|
|
29
|
+
deviceNames = Array.isArray(devices)
|
|
30
|
+
? devices.map(nameMapper)
|
|
31
|
+
: _.flatMap(_.values(devices)).map(nameMapper);
|
|
27
32
|
} catch {}
|
|
28
33
|
throw new Error(
|
|
29
34
|
`'deviceName' must be provided in order to create a new Simulator for ${platform} platform. ` +
|
package/lib/driver.ts
CHANGED
|
@@ -601,7 +601,7 @@ export class XCUITestDriver
|
|
|
601
601
|
this.opts.useNewWDA = util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
|
|
602
602
|
|
|
603
603
|
if (caps.commandTimeouts) {
|
|
604
|
-
caps.commandTimeouts = normalizeCommandTimeouts(caps.commandTimeouts);
|
|
604
|
+
caps.commandTimeouts = normalizeCommandTimeouts(caps.commandTimeouts as string | Record<string, number>);
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
if (_.isString(caps.webDriverAgentUrl)) {
|
|
@@ -1547,9 +1547,11 @@ export class XCUITestDriver
|
|
|
1547
1547
|
};
|
|
1548
1548
|
}
|
|
1549
1549
|
|
|
1550
|
-
const appBundleVersion =
|
|
1551
|
-
|
|
1552
|
-
|
|
1550
|
+
const appBundleVersion = (
|
|
1551
|
+
this.isRealDevice()
|
|
1552
|
+
? (await (this.device as RealDevice).fetchAppInfo(bundleId))
|
|
1553
|
+
: (await (this.device as Simulator).simctl.appInfo(bundleId))
|
|
1554
|
+
)?.CFBundleVersion;
|
|
1553
1555
|
this.log.debug(`CFBundleVersion from installed app info: ${appBundleVersion}`);
|
|
1554
1556
|
if (!appBundleVersion) {
|
|
1555
1557
|
return {
|
package/lib/logger.ts
ADDED