appium-xcuitest-driver 10.3.0 → 10.4.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 +6 -0
- package/build/lib/commands/active-app-info.d.ts +9 -0
- package/build/lib/commands/active-app-info.d.ts.map +1 -0
- package/build/lib/commands/active-app-info.js +14 -0
- package/build/lib/commands/active-app-info.js.map +1 -0
- package/build/lib/commands/alert.d.ts +42 -45
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +66 -62
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +150 -153
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +300 -286
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/app-strings.d.ts +14 -17
- package/build/lib/commands/app-strings.d.ts.map +1 -1
- package/build/lib/commands/app-strings.js +23 -24
- package/build/lib/commands/app-strings.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +19 -22
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +56 -56
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/audit.d.ts +22 -17
- package/build/lib/commands/audit.d.ts.map +1 -1
- package/build/lib/commands/audit.js +17 -18
- package/build/lib/commands/audit.js.map +1 -1
- package/build/lib/commands/battery.d.ts +11 -14
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +36 -37
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/biometric.d.ts +30 -33
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +42 -41
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/certificate.d.ts +48 -45
- package/build/lib/commands/certificate.d.ts.map +1 -1
- package/build/lib/commands/certificate.js +218 -205
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/clipboard.d.ts +19 -22
- package/build/lib/commands/clipboard.d.ts.map +1 -1
- package/build/lib/commands/clipboard.js +30 -30
- package/build/lib/commands/clipboard.js.map +1 -1
- package/build/lib/commands/condition.d.ts +49 -26
- package/build/lib/commands/condition.d.ts.map +1 -1
- package/build/lib/commands/condition.js +87 -86
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/content-size.d.ts +26 -29
- package/build/lib/commands/content-size.d.ts.map +1 -1
- package/build/lib/commands/content-size.js +36 -36
- package/build/lib/commands/content-size.js.map +1 -1
- package/build/lib/commands/context.d.ts +161 -108
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +530 -517
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceInfo.d.ts +9 -12
- package/build/lib/commands/deviceInfo.d.ts.map +1 -1
- package/build/lib/commands/deviceInfo.js +17 -18
- package/build/lib/commands/deviceInfo.js.map +1 -1
- package/build/lib/commands/element.d.ts +102 -105
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +337 -323
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +24 -19
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +63 -62
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-movement.d.ts +77 -80
- package/build/lib/commands/file-movement.d.ts.map +1 -1
- package/build/lib/commands/file-movement.js +130 -124
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/find.d.ts +18 -21
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +158 -156
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +124 -116
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +248 -232
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +43 -46
- package/build/lib/commands/geolocation.d.ts.map +1 -1
- package/build/lib/commands/geolocation.js +10 -11
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/gesture.d.ts +273 -276
- package/build/lib/commands/gesture.d.ts.map +1 -1
- package/build/lib/commands/gesture.js +506 -492
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/increase-contrast.d.ts +20 -23
- package/build/lib/commands/increase-contrast.d.ts.map +1 -1
- package/build/lib/commands/increase-contrast.js +30 -30
- package/build/lib/commands/increase-contrast.js.map +1 -1
- package/build/lib/commands/iohid.d.ts +1370 -1373
- package/build/lib/commands/iohid.d.ts.map +1 -1
- package/build/lib/commands/iohid.js +30 -31
- package/build/lib/commands/iohid.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +29 -32
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +53 -51
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/keychains.d.ts +9 -12
- package/build/lib/commands/keychains.d.ts.map +1 -1
- package/build/lib/commands/keychains.js +13 -14
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts +16 -19
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +25 -26
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.d.ts +36 -39
- package/build/lib/commands/location.d.ts.map +1 -1
- package/build/lib/commands/location.js +99 -98
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/lock.d.ts +21 -24
- package/build/lib/commands/lock.d.ts.map +1 -1
- package/build/lib/commands/lock.js +39 -38
- package/build/lib/commands/lock.js.map +1 -1
- package/build/lib/commands/log.d.ts +43 -37
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +174 -171
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -12
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +37 -38
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/navigation.d.ts +30 -33
- package/build/lib/commands/navigation.d.ts.map +1 -1
- package/build/lib/commands/navigation.js +92 -92
- package/build/lib/commands/navigation.js.map +1 -1
- package/build/lib/commands/notifications.d.ts +26 -29
- package/build/lib/commands/notifications.d.ts.map +1 -1
- package/build/lib/commands/notifications.js +53 -53
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts +21 -24
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +37 -37
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.d.ts +39 -26
- package/build/lib/commands/pcap.d.ts.map +1 -1
- package/build/lib/commands/pcap.js +81 -81
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.d.ts +63 -44
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -105
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +33 -36
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +66 -65
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/proxy-helper.d.ts +12 -15
- package/build/lib/commands/proxy-helper.d.ts.map +1 -1
- package/build/lib/commands/proxy-helper.js +53 -54
- package/build/lib/commands/proxy-helper.js.map +1 -1
- package/build/lib/commands/record-audio.d.ts +49 -29
- package/build/lib/commands/record-audio.d.ts.map +1 -1
- package/build/lib/commands/record-audio.js +100 -104
- package/build/lib/commands/record-audio.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +54 -18
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +127 -129
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/screenshots.d.ts +14 -17
- package/build/lib/commands/screenshots.d.ts.map +1 -1
- package/build/lib/commands/screenshots.js +108 -107
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/simctl.d.ts +11 -14
- package/build/lib/commands/simctl.d.ts.map +1 -1
- package/build/lib/commands/simctl.js +23 -26
- package/build/lib/commands/simctl.js.map +1 -1
- package/build/lib/commands/source.d.ts +14 -17
- package/build/lib/commands/source.d.ts.map +1 -1
- package/build/lib/commands/source.js +40 -43
- package/build/lib/commands/source.js.map +1 -1
- package/build/lib/commands/timeouts.d.ts +44 -33
- package/build/lib/commands/timeouts.d.ts.map +1 -1
- package/build/lib/commands/timeouts.js +65 -63
- package/build/lib/commands/timeouts.js.map +1 -1
- package/build/lib/commands/web.d.ts +247 -197
- package/build/lib/commands/web.d.ts.map +1 -1
- package/build/lib/commands/web.js +815 -786
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.d.ts +63 -66
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
- package/build/lib/commands/xctest-record-screen.js +103 -102
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/commands/xctest.d.ts +55 -51
- package/build/lib/commands/xctest.d.ts.map +1 -1
- package/build/lib/commands/xctest.js +116 -117
- package/build/lib/commands/xctest.js.map +1 -1
- package/build/lib/driver.d.ts +278 -1597
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +319 -235
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +9 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/lib/commands/active-app-info.js +12 -0
- package/lib/commands/alert.js +68 -65
- package/lib/commands/app-management.js +308 -301
- package/lib/commands/app-strings.js +24 -26
- package/lib/commands/appearance.js +54 -56
- package/lib/commands/audit.js +18 -20
- package/lib/commands/battery.js +35 -37
- package/lib/commands/biometric.js +44 -46
- package/lib/commands/certificate.js +226 -215
- package/lib/commands/clipboard.js +30 -32
- package/lib/commands/condition.js +98 -100
- package/lib/commands/content-size.js +36 -38
- package/lib/commands/context.js +495 -490
- package/lib/commands/deviceInfo.js +19 -20
- package/lib/commands/element.js +367 -357
- package/lib/commands/execute.js +72 -72
- package/lib/commands/file-movement.js +132 -134
- package/lib/commands/find.js +160 -159
- package/lib/commands/general.js +238 -231
- package/lib/commands/geolocation.js +6 -14
- package/lib/commands/gesture.js +525 -515
- package/lib/commands/increase-contrast.js +30 -32
- package/lib/commands/iohid.js +32 -34
- package/lib/commands/keyboard.js +49 -51
- package/lib/commands/keychains.js +12 -14
- package/lib/commands/localization.js +24 -26
- package/lib/commands/location.js +102 -104
- package/lib/commands/lock.js +38 -38
- package/lib/commands/log.js +197 -198
- package/lib/commands/memory.js +40 -42
- package/lib/commands/navigation.js +96 -100
- package/lib/commands/notifications.js +57 -59
- package/lib/commands/pasteboard.js +37 -39
- package/lib/commands/pcap.js +84 -86
- package/lib/commands/performance.js +132 -133
- package/lib/commands/permissions.js +67 -69
- package/lib/commands/proxy-helper.js +60 -61
- package/lib/commands/record-audio.js +115 -120
- package/lib/commands/recordscreen.js +145 -149
- package/lib/commands/screenshots.js +116 -116
- package/lib/commands/simctl.js +25 -29
- package/lib/commands/source.js +42 -46
- package/lib/commands/timeouts.js +59 -63
- package/lib/commands/web.js +878 -858
- package/lib/commands/xctest-record-screen.js +103 -105
- package/lib/commands/xctest.js +134 -139
- package/lib/driver.js +287 -235
- package/lib/execute-method-map.ts +9 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/build/lib/commands/activeAppInfo.d.ts +0 -12
- package/build/lib/commands/activeAppInfo.d.ts.map +0 -1
- package/build/lib/commands/activeAppInfo.js +0 -15
- package/build/lib/commands/activeAppInfo.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -96
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -100
- package/build/lib/commands/index.js.map +0 -1
- package/lib/commands/activeAppInfo.js +0 -14
- package/lib/commands/index.js +0 -95
package/lib/commands/element.js
CHANGED
|
@@ -2,6 +2,373 @@ import _ from 'lodash';
|
|
|
2
2
|
import {errors} from 'appium/driver';
|
|
3
3
|
import {util} from 'appium/support';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @this {XCUITestDriver}
|
|
7
|
+
*/
|
|
8
|
+
export async function elementDisplayed(el) {
|
|
9
|
+
el = util.unwrapElement(el);
|
|
10
|
+
if (this.isWebContext()) {
|
|
11
|
+
const atomsElement = this.getAtomsElement(el);
|
|
12
|
+
return await this.executeAtom('is_displayed', [atomsElement]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return await this.proxyCommand(`/element/${el}/displayed`, 'GET');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @this {XCUITestDriver}
|
|
20
|
+
*/
|
|
21
|
+
export async function elementEnabled(el) {
|
|
22
|
+
el = util.unwrapElement(el);
|
|
23
|
+
if (this.isWebContext()) {
|
|
24
|
+
const atomsElement = this.getAtomsElement(el);
|
|
25
|
+
return await this.executeAtom('is_enabled', [atomsElement]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return await this.proxyCommand(`/element/${el}/enabled`, 'GET');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @this {XCUITestDriver}
|
|
33
|
+
*/
|
|
34
|
+
export async function elementSelected(el) {
|
|
35
|
+
el = util.unwrapElement(el);
|
|
36
|
+
if (this.isWebContext()) {
|
|
37
|
+
const atomsElement = this.getAtomsElement(el);
|
|
38
|
+
return await this.executeAtom('is_selected', [atomsElement]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return await this.proxyCommand(`/element/${el}/selected`, 'GET');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @this {XCUITestDriver}
|
|
46
|
+
*/
|
|
47
|
+
export async function getName(el) {
|
|
48
|
+
el = util.unwrapElement(el);
|
|
49
|
+
if (this.isWebContext()) {
|
|
50
|
+
const atomsElement = this.getAtomsElement(el);
|
|
51
|
+
const script = 'return arguments[0].tagName.toLowerCase()';
|
|
52
|
+
return await this.executeAtom('execute_script', [script, [atomsElement]]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return await this.proxyCommand(`/element/${el}/name`, 'GET');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @this {XCUITestDriver}
|
|
60
|
+
*/
|
|
61
|
+
export async function getNativeAttribute(attribute, el) {
|
|
62
|
+
if (attribute === 'contentSize') {
|
|
63
|
+
// don't proxy requests for the content size of a scrollable element
|
|
64
|
+
return await this.getContentSize(el);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
el = util.unwrapElement(el);
|
|
68
|
+
|
|
69
|
+
// otherwise let WDA handle attribute requests
|
|
70
|
+
let value = /** @type {string|number|null|undefined|boolean} */ (
|
|
71
|
+
await this.proxyCommand(`/element/${el}/attribute/${attribute}`, 'GET')
|
|
72
|
+
);
|
|
73
|
+
// Transform the result for the case when WDA returns an integer representation for a boolean value
|
|
74
|
+
if ([0, 1].includes(/** @type {number} */ (value))) {
|
|
75
|
+
value = !!value;
|
|
76
|
+
}
|
|
77
|
+
// The returned value must be of type string according to https://www.w3.org/TR/webdriver/#get-element-attribute
|
|
78
|
+
return _.isNull(value) || _.isString(value) ? value : JSON.stringify(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @this {XCUITestDriver}
|
|
83
|
+
*/
|
|
84
|
+
export async function getAttribute(attribute, el) {
|
|
85
|
+
el = util.unwrapElement(el);
|
|
86
|
+
if (!this.isWebContext()) {
|
|
87
|
+
return await this.getNativeAttribute(attribute, el);
|
|
88
|
+
}
|
|
89
|
+
const atomsElement = this.getAtomsElement(el);
|
|
90
|
+
return await this.executeAtom('get_attribute_value', [atomsElement, attribute]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @this {XCUITestDriver}
|
|
95
|
+
*/
|
|
96
|
+
export async function getProperty(property, el) {
|
|
97
|
+
el = util.unwrapElement(el);
|
|
98
|
+
if (!this.isWebContext()) {
|
|
99
|
+
return await this.getNativeAttribute(property, el);
|
|
100
|
+
}
|
|
101
|
+
const atomsElement = this.getAtomsElement(el);
|
|
102
|
+
return await this.executeAtom('get_attribute_value', [atomsElement, property]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @this {XCUITestDriver}
|
|
107
|
+
*/
|
|
108
|
+
export async function getText(el) {
|
|
109
|
+
el = util.unwrapElement(el);
|
|
110
|
+
if (!this.isWebContext()) {
|
|
111
|
+
return await this.proxyCommand(`/element/${el}/text`, 'GET');
|
|
112
|
+
}
|
|
113
|
+
let atomsElement = this.getAtomsElement(el);
|
|
114
|
+
return await this.executeAtom('get_text', [atomsElement]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @this {XCUITestDriver}
|
|
119
|
+
* @returns {Promise<import('@appium/types').Rect>}
|
|
120
|
+
*/
|
|
121
|
+
export async function getElementRect(el) {
|
|
122
|
+
if (this.isWebContext()) {
|
|
123
|
+
// Mobile safari doesn't support rect
|
|
124
|
+
const {x, y} = await this.getLocation(el);
|
|
125
|
+
const {width, height} = await this.getSize(el);
|
|
126
|
+
return {x, y, width, height};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
el = util.unwrapElement(el);
|
|
130
|
+
return await this.getNativeRect(el);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the position of an element on screen
|
|
135
|
+
*
|
|
136
|
+
* @param {string|Element} elementId - the element ID
|
|
137
|
+
* @returns {Promise<Position>} The position of the element
|
|
138
|
+
* @deprecated Use {@linkcode XCUITestDriver.getElementRect} instead
|
|
139
|
+
* @this {XCUITestDriver}
|
|
140
|
+
*/
|
|
141
|
+
export async function getLocation(elementId) {
|
|
142
|
+
const el = util.unwrapElement(elementId);
|
|
143
|
+
if (this.isWebContext()) {
|
|
144
|
+
const atomsElement = this.getAtomsElement(el);
|
|
145
|
+
let loc = await this.executeAtom('get_top_left_coordinates', [atomsElement]);
|
|
146
|
+
if (this.opts.absoluteWebLocations) {
|
|
147
|
+
const script =
|
|
148
|
+
'return [' +
|
|
149
|
+
'Math.max(window.pageXOffset,document.documentElement.scrollLeft,document.body.scrollLeft),' +
|
|
150
|
+
'Math.max(window.pageYOffset,document.documentElement.scrollTop,document.body.scrollTop)];';
|
|
151
|
+
const [xOffset, yOffset] = /** @type {[number, number]} */ (await this.execute(script));
|
|
152
|
+
loc.x += xOffset;
|
|
153
|
+
loc.y += yOffset;
|
|
154
|
+
}
|
|
155
|
+
return loc;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const rect = await this.getElementRect(el);
|
|
159
|
+
return {x: rect.x, y: rect.y};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Alias for {@linkcode XCUITestDriver.getLocation}
|
|
164
|
+
* @param {string|Element} elementId - the element ID
|
|
165
|
+
* @returns {Promise<Position>} The position of the element
|
|
166
|
+
* @deprecated Use {@linkcode XCUITestDriver.getElementRect} instead
|
|
167
|
+
* @this {XCUITestDriver}
|
|
168
|
+
*/
|
|
169
|
+
export async function getLocationInView(elementId) {
|
|
170
|
+
return await this.getLocation(elementId);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get the size of an element
|
|
175
|
+
* @param {string|Element} el - the element ID
|
|
176
|
+
* @returns {Promise<Size>} The position of the element
|
|
177
|
+
* @this {XCUITestDriver}
|
|
178
|
+
*/
|
|
179
|
+
export async function getSize(el) {
|
|
180
|
+
el = util.unwrapElement(el);
|
|
181
|
+
if (this.isWebContext()) {
|
|
182
|
+
return await this.executeAtom('get_size', [this.getAtomsElement(el)]);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const rect = await this.getElementRect(el);
|
|
186
|
+
return {width: rect.width, height: rect.height};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Alias for {@linkcode setValue}
|
|
191
|
+
*
|
|
192
|
+
* @param {string} value - the value to set
|
|
193
|
+
* @param {string} el - the element to set the value of
|
|
194
|
+
* @deprecated
|
|
195
|
+
* @this {XCUITestDriver}
|
|
196
|
+
*/
|
|
197
|
+
export async function setValueImmediate(value, el) {
|
|
198
|
+
// WDA does not provide no way to set the value directly
|
|
199
|
+
this.log.info(
|
|
200
|
+
'There is currently no way to bypass typing using XCUITest. Setting value through keyboard',
|
|
201
|
+
);
|
|
202
|
+
await this.setValue(value, el);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @this {XCUITestDriver}
|
|
207
|
+
*/
|
|
208
|
+
export async function setValue(value, el) {
|
|
209
|
+
el = util.unwrapElement(el);
|
|
210
|
+
if (!this.isWebContext()) {
|
|
211
|
+
await this.proxyCommand(`/element/${el}/value`, 'POST', {
|
|
212
|
+
value: prepareInputValue(value),
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const atomsElement = this.getAtomsElement(el);
|
|
218
|
+
await this.executeAtom('click', [atomsElement]);
|
|
219
|
+
|
|
220
|
+
if (this.opts.sendKeyStrategy !== 'oneByOne') {
|
|
221
|
+
await this.setValueWithWebAtom(atomsElement, value);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
for (const char of prepareInputValue(value)) {
|
|
225
|
+
await this.setValueWithWebAtom(atomsElement, char);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Set value with Atom for Web. This method calls `type` atom only.
|
|
231
|
+
* Expected to be called as part of {@linkcode setValue}.
|
|
232
|
+
* @this {XCUITestDriver}
|
|
233
|
+
* @param {import('./types').AtomsElement<string>} atomsElement A target element to type the given value.
|
|
234
|
+
* @param {string|string[]} value The actual text to type.
|
|
235
|
+
*/
|
|
236
|
+
export async function setValueWithWebAtom(atomsElement, value) {
|
|
237
|
+
await this.executeAtom('type', [atomsElement, value]);
|
|
238
|
+
|
|
239
|
+
if (this.opts.skipTriggerInputEventAfterSendkeys) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function triggerInputEvent(/** @type {EventTarget & {_valueTracker?: any}} */input) {
|
|
244
|
+
let lastValue = '';
|
|
245
|
+
let event = new Event('input', { bubbles: true });
|
|
246
|
+
let tracker = input._valueTracker;
|
|
247
|
+
if (tracker) {
|
|
248
|
+
tracker.setValue(lastValue);
|
|
249
|
+
}
|
|
250
|
+
input.dispatchEvent(event);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const scriptAsString = `return (${triggerInputEvent}).apply(null, arguments)`;
|
|
254
|
+
await this.executeAtom('execute_script', [scriptAsString, [atomsElement]]);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Send keys to the app
|
|
259
|
+
* @param {string[]} value - Array of keys to send
|
|
260
|
+
* @this {XCUITestDriver}
|
|
261
|
+
* @deprecated Use {@linkcode XCUITestDriver.setValue} instead
|
|
262
|
+
*/
|
|
263
|
+
export async function keys(value) {
|
|
264
|
+
await this.proxyCommand('/wda/keys', 'POST', {
|
|
265
|
+
value: prepareInputValue(value),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @this {XCUITestDriver}
|
|
271
|
+
*/
|
|
272
|
+
export async function clear(el) {
|
|
273
|
+
el = util.unwrapElement(el);
|
|
274
|
+
if (this.isWebContext()) {
|
|
275
|
+
const atomsElement = this.getAtomsElement(el);
|
|
276
|
+
await this.executeAtom('clear', [atomsElement]);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
await this.proxyCommand(`/element/${el}/clear`, 'POST');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @this {XCUITestDriver}
|
|
284
|
+
*/
|
|
285
|
+
export async function getContentSize(el) {
|
|
286
|
+
if (this.isWebContext()) {
|
|
287
|
+
throw new errors.NotYetImplementedError(
|
|
288
|
+
'Support for getContentSize for web context is not yet implemented. Please contact an Appium dev',
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const type = await this.getAttribute('type', el);
|
|
293
|
+
|
|
294
|
+
if (type !== 'XCUIElementTypeTable' && type !== 'XCUIElementTypeCollectionView') {
|
|
295
|
+
throw new Error(
|
|
296
|
+
`Can't get content size for type '${type}', only for ` + `tables and collection views`,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
let locator = '*';
|
|
300
|
+
if (type === 'XCUIElementTypeTable') {
|
|
301
|
+
// only find table cells, not just any children
|
|
302
|
+
locator = 'XCUIElementTypeCell';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let contentHeight = 0;
|
|
306
|
+
const children = await this.findElOrEls(`class chain`, locator, true, el);
|
|
307
|
+
if (children.length === 1) {
|
|
308
|
+
// if we know there's only one element, we can optimize to make just one
|
|
309
|
+
// call to WDA
|
|
310
|
+
const rect = await this.getElementRect(_.head(children));
|
|
311
|
+
contentHeight = rect.height;
|
|
312
|
+
} else if (children.length) {
|
|
313
|
+
// otherwise if we have multiple elements, logic differs based on element
|
|
314
|
+
// type
|
|
315
|
+
switch (type) {
|
|
316
|
+
case 'XCUIElementTypeTable': {
|
|
317
|
+
const firstRect = await this.getElementRect(_.head(children));
|
|
318
|
+
const lastRect = await this.getElementRect(_.last(children));
|
|
319
|
+
contentHeight = lastRect.y + lastRect.height - firstRect.y;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case 'XCUIElementTypeCollectionView': {
|
|
323
|
+
let elsInRow = 1; // we know there must be at least one element in the row
|
|
324
|
+
let firstRect = await this.getElementRect(_.head(children));
|
|
325
|
+
let initialRects = [firstRect];
|
|
326
|
+
for (let i = 1; i < children.length; i++) {
|
|
327
|
+
const rect = await this.getElementRect(children[i]);
|
|
328
|
+
initialRects.push(rect);
|
|
329
|
+
if (rect.y !== firstRect.y) {
|
|
330
|
+
elsInRow = i;
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const spaceBetweenEls =
|
|
335
|
+
initialRects[elsInRow].y -
|
|
336
|
+
initialRects[elsInRow - 1].y -
|
|
337
|
+
initialRects[elsInRow - 1].height;
|
|
338
|
+
const numRows = Math.ceil(children.length / elsInRow);
|
|
339
|
+
|
|
340
|
+
// assume all cells are the same height
|
|
341
|
+
contentHeight = numRows * firstRect.height + spaceBetweenEls * (numRows - 1);
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
default:
|
|
345
|
+
throw new Error(
|
|
346
|
+
`Programming error: type '${type}' was not ` +
|
|
347
|
+
`valid but should have already been rejected`,
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const size = await this.getSize(el);
|
|
352
|
+
const origin = await this.getLocationInView(el);
|
|
353
|
+
// attributes have to be strings, so stringify this up
|
|
354
|
+
return JSON.stringify({
|
|
355
|
+
width: size.width,
|
|
356
|
+
height: size.height,
|
|
357
|
+
top: origin.y,
|
|
358
|
+
left: origin.x,
|
|
359
|
+
scrollableOffset: contentHeight,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @this {XCUITestDriver}
|
|
365
|
+
* @returns {Promise<Rect>}
|
|
366
|
+
*/
|
|
367
|
+
export async function getNativeRect(el) {
|
|
368
|
+
return /** @type {Rect} */ (await this.proxyCommand(`/element/${el}/rect`, 'GET'));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
5
372
|
/**
|
|
6
373
|
* Prepares the input value to be passed as an argument to WDA.
|
|
7
374
|
*
|
|
@@ -47,363 +414,6 @@ function prepareInputValue(inp) {
|
|
|
47
414
|
});
|
|
48
415
|
}
|
|
49
416
|
|
|
50
|
-
const commands = {
|
|
51
|
-
/**
|
|
52
|
-
* @this {XCUITestDriver}
|
|
53
|
-
*/
|
|
54
|
-
async elementDisplayed(el) {
|
|
55
|
-
el = util.unwrapElement(el);
|
|
56
|
-
if (this.isWebContext()) {
|
|
57
|
-
const atomsElement = this.getAtomsElement(el);
|
|
58
|
-
return await this.executeAtom('is_displayed', [atomsElement]);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return await this.proxyCommand(`/element/${el}/displayed`, 'GET');
|
|
62
|
-
},
|
|
63
|
-
/**
|
|
64
|
-
* @this {XCUITestDriver}
|
|
65
|
-
*/
|
|
66
|
-
async elementEnabled(el) {
|
|
67
|
-
el = util.unwrapElement(el);
|
|
68
|
-
if (this.isWebContext()) {
|
|
69
|
-
const atomsElement = this.getAtomsElement(el);
|
|
70
|
-
return await this.executeAtom('is_enabled', [atomsElement]);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return await this.proxyCommand(`/element/${el}/enabled`, 'GET');
|
|
74
|
-
},
|
|
75
|
-
/**
|
|
76
|
-
* @this {XCUITestDriver}
|
|
77
|
-
*/
|
|
78
|
-
async elementSelected(el) {
|
|
79
|
-
el = util.unwrapElement(el);
|
|
80
|
-
if (this.isWebContext()) {
|
|
81
|
-
const atomsElement = this.getAtomsElement(el);
|
|
82
|
-
return await this.executeAtom('is_selected', [atomsElement]);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return await this.proxyCommand(`/element/${el}/selected`, 'GET');
|
|
86
|
-
},
|
|
87
|
-
/**
|
|
88
|
-
* @this {XCUITestDriver}
|
|
89
|
-
*/
|
|
90
|
-
async getName(el) {
|
|
91
|
-
el = util.unwrapElement(el);
|
|
92
|
-
if (this.isWebContext()) {
|
|
93
|
-
const atomsElement = this.getAtomsElement(el);
|
|
94
|
-
const script = 'return arguments[0].tagName.toLowerCase()';
|
|
95
|
-
return await this.executeAtom('execute_script', [script, [atomsElement]]);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return await this.proxyCommand(`/element/${el}/name`, 'GET');
|
|
99
|
-
},
|
|
100
|
-
/**
|
|
101
|
-
* @this {XCUITestDriver}
|
|
102
|
-
*/
|
|
103
|
-
async getNativeAttribute(attribute, el) {
|
|
104
|
-
if (attribute === 'contentSize') {
|
|
105
|
-
// don't proxy requests for the content size of a scrollable element
|
|
106
|
-
return await this.getContentSize(el);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
el = util.unwrapElement(el);
|
|
110
|
-
|
|
111
|
-
// otherwise let WDA handle attribute requests
|
|
112
|
-
let value = /** @type {string|number|null|undefined|boolean} */ (
|
|
113
|
-
await this.proxyCommand(`/element/${el}/attribute/${attribute}`, 'GET')
|
|
114
|
-
);
|
|
115
|
-
// Transform the result for the case when WDA returns an integer representation for a boolean value
|
|
116
|
-
if ([0, 1].includes(/** @type {number} */ (value))) {
|
|
117
|
-
value = !!value;
|
|
118
|
-
}
|
|
119
|
-
// The returned value must be of type string according to https://www.w3.org/TR/webdriver/#get-element-attribute
|
|
120
|
-
return _.isNull(value) || _.isString(value) ? value : JSON.stringify(value);
|
|
121
|
-
},
|
|
122
|
-
/**
|
|
123
|
-
* @this {XCUITestDriver}
|
|
124
|
-
*/
|
|
125
|
-
async getAttribute(attribute, el) {
|
|
126
|
-
el = util.unwrapElement(el);
|
|
127
|
-
if (!this.isWebContext()) {
|
|
128
|
-
return await this.getNativeAttribute(attribute, el);
|
|
129
|
-
}
|
|
130
|
-
const atomsElement = this.getAtomsElement(el);
|
|
131
|
-
return await this.executeAtom('get_attribute_value', [atomsElement, attribute]);
|
|
132
|
-
},
|
|
133
|
-
/**
|
|
134
|
-
* @this {XCUITestDriver}
|
|
135
|
-
*/
|
|
136
|
-
async getProperty(property, el) {
|
|
137
|
-
el = util.unwrapElement(el);
|
|
138
|
-
if (!this.isWebContext()) {
|
|
139
|
-
return await this.getNativeAttribute(property, el);
|
|
140
|
-
}
|
|
141
|
-
const atomsElement = this.getAtomsElement(el);
|
|
142
|
-
return await this.executeAtom('get_attribute_value', [atomsElement, property]);
|
|
143
|
-
},
|
|
144
|
-
/**
|
|
145
|
-
* @this {XCUITestDriver}
|
|
146
|
-
*/
|
|
147
|
-
async getText(el) {
|
|
148
|
-
el = util.unwrapElement(el);
|
|
149
|
-
if (!this.isWebContext()) {
|
|
150
|
-
return await this.proxyCommand(`/element/${el}/text`, 'GET');
|
|
151
|
-
}
|
|
152
|
-
let atomsElement = this.getAtomsElement(el);
|
|
153
|
-
return await this.executeAtom('get_text', [atomsElement]);
|
|
154
|
-
},
|
|
155
|
-
/**
|
|
156
|
-
* @this {XCUITestDriver}
|
|
157
|
-
* @returns {Promise<import('@appium/types').Rect>}
|
|
158
|
-
*/
|
|
159
|
-
async getElementRect(el) {
|
|
160
|
-
if (this.isWebContext()) {
|
|
161
|
-
// Mobile safari doesn't support rect
|
|
162
|
-
const {x, y} = await this.getLocation(el);
|
|
163
|
-
const {width, height} = await this.getSize(el);
|
|
164
|
-
return {x, y, width, height};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
el = util.unwrapElement(el);
|
|
168
|
-
return await this.getNativeRect(el);
|
|
169
|
-
},
|
|
170
|
-
/**
|
|
171
|
-
* Get the position of an element on screen
|
|
172
|
-
*
|
|
173
|
-
* @param {string|Element} elementId - the element ID
|
|
174
|
-
* @returns {Promise<Position>} The position of the element
|
|
175
|
-
* @deprecated Use {@linkcode XCUITestDriver.getElementRect} instead
|
|
176
|
-
* @this {XCUITestDriver}
|
|
177
|
-
*/
|
|
178
|
-
async getLocation(elementId) {
|
|
179
|
-
const el = util.unwrapElement(elementId);
|
|
180
|
-
if (this.isWebContext()) {
|
|
181
|
-
const atomsElement = this.getAtomsElement(el);
|
|
182
|
-
let loc = await this.executeAtom('get_top_left_coordinates', [atomsElement]);
|
|
183
|
-
if (this.opts.absoluteWebLocations) {
|
|
184
|
-
const script =
|
|
185
|
-
'return [' +
|
|
186
|
-
'Math.max(window.pageXOffset,document.documentElement.scrollLeft,document.body.scrollLeft),' +
|
|
187
|
-
'Math.max(window.pageYOffset,document.documentElement.scrollTop,document.body.scrollTop)];';
|
|
188
|
-
const [xOffset, yOffset] = /** @type {[number, number]} */ (await this.execute(script));
|
|
189
|
-
loc.x += xOffset;
|
|
190
|
-
loc.y += yOffset;
|
|
191
|
-
}
|
|
192
|
-
return loc;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const rect = await this.getElementRect(el);
|
|
196
|
-
return {x: rect.x, y: rect.y};
|
|
197
|
-
},
|
|
198
|
-
/**
|
|
199
|
-
* Alias for {@linkcode XCUITestDriver.getLocation}
|
|
200
|
-
* @param {string|Element} elementId - the element ID
|
|
201
|
-
* @returns {Promise<Position>} The position of the element
|
|
202
|
-
* @deprecated Use {@linkcode XCUITestDriver.getElementRect} instead
|
|
203
|
-
* @this {XCUITestDriver}
|
|
204
|
-
*/
|
|
205
|
-
async getLocationInView(elementId) {
|
|
206
|
-
return await this.getLocation(elementId);
|
|
207
|
-
},
|
|
208
|
-
/**
|
|
209
|
-
* Get the size of an element
|
|
210
|
-
* @param {string|Element} el - the element ID
|
|
211
|
-
* @returns {Promise<Size>} The position of the element
|
|
212
|
-
* @this {XCUITestDriver}
|
|
213
|
-
*/
|
|
214
|
-
async getSize(el) {
|
|
215
|
-
el = util.unwrapElement(el);
|
|
216
|
-
if (this.isWebContext()) {
|
|
217
|
-
return await this.executeAtom('get_size', [this.getAtomsElement(el)]);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const rect = await this.getElementRect(el);
|
|
221
|
-
return {width: rect.width, height: rect.height};
|
|
222
|
-
},
|
|
223
|
-
/**
|
|
224
|
-
* Alias for {@linkcode setValue}
|
|
225
|
-
*
|
|
226
|
-
* @param {string} value - the value to set
|
|
227
|
-
* @param {string} el - the element to set the value of
|
|
228
|
-
* @deprecated
|
|
229
|
-
* @this {XCUITestDriver}
|
|
230
|
-
*/
|
|
231
|
-
async setValueImmediate(value, el) {
|
|
232
|
-
// WDA does not provide no way to set the value directly
|
|
233
|
-
this.log.info(
|
|
234
|
-
'There is currently no way to bypass typing using XCUITest. Setting value through keyboard',
|
|
235
|
-
);
|
|
236
|
-
await this.setValue(value, el);
|
|
237
|
-
},
|
|
238
|
-
/**
|
|
239
|
-
* @this {XCUITestDriver}
|
|
240
|
-
*/
|
|
241
|
-
async setValue(value, el) {
|
|
242
|
-
el = util.unwrapElement(el);
|
|
243
|
-
if (!this.isWebContext()) {
|
|
244
|
-
await this.proxyCommand(`/element/${el}/value`, 'POST', {
|
|
245
|
-
value: prepareInputValue(value),
|
|
246
|
-
});
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const atomsElement = this.getAtomsElement(el);
|
|
251
|
-
await this.executeAtom('click', [atomsElement]);
|
|
252
|
-
|
|
253
|
-
if (this.opts.sendKeyStrategy !== 'oneByOne') {
|
|
254
|
-
await this.setValueWithWebAtom(atomsElement, value);
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
for (const char of prepareInputValue(value)) {
|
|
258
|
-
await this.setValueWithWebAtom(atomsElement, char);
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Set value with Atom for Web. This method calls `type` atom only.
|
|
264
|
-
* Expected to be called as part of {@linkcode setValue}.
|
|
265
|
-
* @this {XCUITestDriver}
|
|
266
|
-
* @param {import('./types').AtomsElement<string>} atomsElement A target element to type the given value.
|
|
267
|
-
* @param {string|string[]} value The actual text to type.
|
|
268
|
-
*/
|
|
269
|
-
async setValueWithWebAtom(atomsElement, value) {
|
|
270
|
-
await this.executeAtom('type', [atomsElement, value]);
|
|
271
|
-
|
|
272
|
-
if (this.opts.skipTriggerInputEventAfterSendkeys) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function triggerInputEvent(/** @type {EventTarget & {_valueTracker?: any}} */input) {
|
|
277
|
-
let lastValue = '';
|
|
278
|
-
let event = new Event('input', { bubbles: true });
|
|
279
|
-
let tracker = input._valueTracker;
|
|
280
|
-
if (tracker) {
|
|
281
|
-
tracker.setValue(lastValue);
|
|
282
|
-
}
|
|
283
|
-
input.dispatchEvent(event);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const scriptAsString = `return (${triggerInputEvent}).apply(null, arguments)`;
|
|
287
|
-
await this.executeAtom('execute_script', [scriptAsString, [atomsElement]]);
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Send keys to the app
|
|
292
|
-
* @param {string[]} value - Array of keys to send
|
|
293
|
-
* @this {XCUITestDriver}
|
|
294
|
-
* @deprecated Use {@linkcode XCUITestDriver.setValue} instead
|
|
295
|
-
*/
|
|
296
|
-
async keys(value) {
|
|
297
|
-
await this.proxyCommand('/wda/keys', 'POST', {
|
|
298
|
-
value: prepareInputValue(value),
|
|
299
|
-
});
|
|
300
|
-
},
|
|
301
|
-
/**
|
|
302
|
-
* @this {XCUITestDriver}
|
|
303
|
-
*/
|
|
304
|
-
async clear(el) {
|
|
305
|
-
el = util.unwrapElement(el);
|
|
306
|
-
if (this.isWebContext()) {
|
|
307
|
-
const atomsElement = this.getAtomsElement(el);
|
|
308
|
-
await this.executeAtom('clear', [atomsElement]);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
await this.proxyCommand(`/element/${el}/clear`, 'POST');
|
|
312
|
-
},
|
|
313
|
-
/**
|
|
314
|
-
* @this {XCUITestDriver}
|
|
315
|
-
*/
|
|
316
|
-
async getContentSize(el) {
|
|
317
|
-
if (this.isWebContext()) {
|
|
318
|
-
throw new errors.NotYetImplementedError(
|
|
319
|
-
'Support for getContentSize for web context is not yet implemented. Please contact an Appium dev',
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const type = await this.getAttribute('type', el);
|
|
324
|
-
|
|
325
|
-
if (type !== 'XCUIElementTypeTable' && type !== 'XCUIElementTypeCollectionView') {
|
|
326
|
-
throw new Error(
|
|
327
|
-
`Can't get content size for type '${type}', only for ` + `tables and collection views`,
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
let locator = '*';
|
|
331
|
-
if (type === 'XCUIElementTypeTable') {
|
|
332
|
-
// only find table cells, not just any children
|
|
333
|
-
locator = 'XCUIElementTypeCell';
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
let contentHeight = 0;
|
|
337
|
-
const children = await this.findElOrEls(`class chain`, locator, true, el);
|
|
338
|
-
if (children.length === 1) {
|
|
339
|
-
// if we know there's only one element, we can optimize to make just one
|
|
340
|
-
// call to WDA
|
|
341
|
-
const rect = await this.getElementRect(_.head(children));
|
|
342
|
-
contentHeight = rect.height;
|
|
343
|
-
} else if (children.length) {
|
|
344
|
-
// otherwise if we have multiple elements, logic differs based on element
|
|
345
|
-
// type
|
|
346
|
-
switch (type) {
|
|
347
|
-
case 'XCUIElementTypeTable': {
|
|
348
|
-
const firstRect = await this.getElementRect(_.head(children));
|
|
349
|
-
const lastRect = await this.getElementRect(_.last(children));
|
|
350
|
-
contentHeight = lastRect.y + lastRect.height - firstRect.y;
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
case 'XCUIElementTypeCollectionView': {
|
|
354
|
-
let elsInRow = 1; // we know there must be at least one element in the row
|
|
355
|
-
let firstRect = await this.getElementRect(_.head(children));
|
|
356
|
-
let initialRects = [firstRect];
|
|
357
|
-
for (let i = 1; i < children.length; i++) {
|
|
358
|
-
const rect = await this.getElementRect(children[i]);
|
|
359
|
-
initialRects.push(rect);
|
|
360
|
-
if (rect.y !== firstRect.y) {
|
|
361
|
-
elsInRow = i;
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
const spaceBetweenEls =
|
|
366
|
-
initialRects[elsInRow].y -
|
|
367
|
-
initialRects[elsInRow - 1].y -
|
|
368
|
-
initialRects[elsInRow - 1].height;
|
|
369
|
-
const numRows = Math.ceil(children.length / elsInRow);
|
|
370
|
-
|
|
371
|
-
// assume all cells are the same height
|
|
372
|
-
contentHeight = numRows * firstRect.height + spaceBetweenEls * (numRows - 1);
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
default:
|
|
376
|
-
throw new Error(
|
|
377
|
-
`Programming error: type '${type}' was not ` +
|
|
378
|
-
`valid but should have already been rejected`,
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
const size = await this.getSize(el);
|
|
383
|
-
const origin = await this.getLocationInView(el);
|
|
384
|
-
// attributes have to be strings, so stringify this up
|
|
385
|
-
return JSON.stringify({
|
|
386
|
-
width: size.width,
|
|
387
|
-
height: size.height,
|
|
388
|
-
top: origin.y,
|
|
389
|
-
left: origin.x,
|
|
390
|
-
scrollableOffset: contentHeight,
|
|
391
|
-
});
|
|
392
|
-
},
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
const extensions = {
|
|
396
|
-
/**
|
|
397
|
-
* @this {XCUITestDriver}
|
|
398
|
-
* @returns {Promise<Rect>}
|
|
399
|
-
*/
|
|
400
|
-
async getNativeRect(el) {
|
|
401
|
-
return /** @type {Rect} */ (await this.proxyCommand(`/element/${el}/rect`, 'GET'));
|
|
402
|
-
},
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
export default {...extensions, ...commands};
|
|
406
|
-
|
|
407
417
|
/**
|
|
408
418
|
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
409
419
|
* @typedef {import('@appium/types').Element} Element
|