appium-xcuitest-driver 10.2.2 → 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.
Files changed (262) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/active-app-info.d.ts +9 -0
  3. package/build/lib/commands/active-app-info.d.ts.map +1 -0
  4. package/build/lib/commands/active-app-info.js +14 -0
  5. package/build/lib/commands/active-app-info.js.map +1 -0
  6. package/build/lib/commands/alert.d.ts +42 -45
  7. package/build/lib/commands/alert.d.ts.map +1 -1
  8. package/build/lib/commands/alert.js +66 -62
  9. package/build/lib/commands/alert.js.map +1 -1
  10. package/build/lib/commands/app-management.d.ts +150 -153
  11. package/build/lib/commands/app-management.d.ts.map +1 -1
  12. package/build/lib/commands/app-management.js +300 -286
  13. package/build/lib/commands/app-management.js.map +1 -1
  14. package/build/lib/commands/app-strings.d.ts +14 -17
  15. package/build/lib/commands/app-strings.d.ts.map +1 -1
  16. package/build/lib/commands/app-strings.js +23 -24
  17. package/build/lib/commands/app-strings.js.map +1 -1
  18. package/build/lib/commands/appearance.d.ts +19 -22
  19. package/build/lib/commands/appearance.d.ts.map +1 -1
  20. package/build/lib/commands/appearance.js +56 -56
  21. package/build/lib/commands/appearance.js.map +1 -1
  22. package/build/lib/commands/audit.d.ts +22 -17
  23. package/build/lib/commands/audit.d.ts.map +1 -1
  24. package/build/lib/commands/audit.js +17 -18
  25. package/build/lib/commands/audit.js.map +1 -1
  26. package/build/lib/commands/battery.d.ts +11 -14
  27. package/build/lib/commands/battery.d.ts.map +1 -1
  28. package/build/lib/commands/battery.js +36 -37
  29. package/build/lib/commands/battery.js.map +1 -1
  30. package/build/lib/commands/biometric.d.ts +30 -33
  31. package/build/lib/commands/biometric.d.ts.map +1 -1
  32. package/build/lib/commands/biometric.js +42 -41
  33. package/build/lib/commands/biometric.js.map +1 -1
  34. package/build/lib/commands/certificate.d.ts +48 -45
  35. package/build/lib/commands/certificate.d.ts.map +1 -1
  36. package/build/lib/commands/certificate.js +218 -205
  37. package/build/lib/commands/certificate.js.map +1 -1
  38. package/build/lib/commands/clipboard.d.ts +19 -22
  39. package/build/lib/commands/clipboard.d.ts.map +1 -1
  40. package/build/lib/commands/clipboard.js +30 -30
  41. package/build/lib/commands/clipboard.js.map +1 -1
  42. package/build/lib/commands/condition.d.ts +49 -26
  43. package/build/lib/commands/condition.d.ts.map +1 -1
  44. package/build/lib/commands/condition.js +87 -86
  45. package/build/lib/commands/condition.js.map +1 -1
  46. package/build/lib/commands/content-size.d.ts +26 -29
  47. package/build/lib/commands/content-size.d.ts.map +1 -1
  48. package/build/lib/commands/content-size.js +36 -36
  49. package/build/lib/commands/content-size.js.map +1 -1
  50. package/build/lib/commands/context.d.ts +161 -108
  51. package/build/lib/commands/context.d.ts.map +1 -1
  52. package/build/lib/commands/context.js +530 -517
  53. package/build/lib/commands/context.js.map +1 -1
  54. package/build/lib/commands/deviceInfo.d.ts +9 -12
  55. package/build/lib/commands/deviceInfo.d.ts.map +1 -1
  56. package/build/lib/commands/deviceInfo.js +17 -18
  57. package/build/lib/commands/deviceInfo.js.map +1 -1
  58. package/build/lib/commands/element.d.ts +102 -105
  59. package/build/lib/commands/element.d.ts.map +1 -1
  60. package/build/lib/commands/element.js +337 -323
  61. package/build/lib/commands/element.js.map +1 -1
  62. package/build/lib/commands/execute.d.ts +24 -19
  63. package/build/lib/commands/execute.d.ts.map +1 -1
  64. package/build/lib/commands/execute.js +63 -62
  65. package/build/lib/commands/execute.js.map +1 -1
  66. package/build/lib/commands/file-movement.d.ts +77 -80
  67. package/build/lib/commands/file-movement.d.ts.map +1 -1
  68. package/build/lib/commands/file-movement.js +130 -124
  69. package/build/lib/commands/file-movement.js.map +1 -1
  70. package/build/lib/commands/find.d.ts +18 -21
  71. package/build/lib/commands/find.d.ts.map +1 -1
  72. package/build/lib/commands/find.js +158 -156
  73. package/build/lib/commands/find.js.map +1 -1
  74. package/build/lib/commands/general.d.ts +124 -116
  75. package/build/lib/commands/general.d.ts.map +1 -1
  76. package/build/lib/commands/general.js +248 -232
  77. package/build/lib/commands/general.js.map +1 -1
  78. package/build/lib/commands/geolocation.d.ts +43 -46
  79. package/build/lib/commands/geolocation.d.ts.map +1 -1
  80. package/build/lib/commands/geolocation.js +10 -11
  81. package/build/lib/commands/geolocation.js.map +1 -1
  82. package/build/lib/commands/gesture.d.ts +273 -276
  83. package/build/lib/commands/gesture.d.ts.map +1 -1
  84. package/build/lib/commands/gesture.js +506 -492
  85. package/build/lib/commands/gesture.js.map +1 -1
  86. package/build/lib/commands/increase-contrast.d.ts +20 -23
  87. package/build/lib/commands/increase-contrast.d.ts.map +1 -1
  88. package/build/lib/commands/increase-contrast.js +30 -30
  89. package/build/lib/commands/increase-contrast.js.map +1 -1
  90. package/build/lib/commands/iohid.d.ts +1370 -1373
  91. package/build/lib/commands/iohid.d.ts.map +1 -1
  92. package/build/lib/commands/iohid.js +30 -31
  93. package/build/lib/commands/iohid.js.map +1 -1
  94. package/build/lib/commands/keyboard.d.ts +29 -32
  95. package/build/lib/commands/keyboard.d.ts.map +1 -1
  96. package/build/lib/commands/keyboard.js +53 -51
  97. package/build/lib/commands/keyboard.js.map +1 -1
  98. package/build/lib/commands/keychains.d.ts +9 -12
  99. package/build/lib/commands/keychains.d.ts.map +1 -1
  100. package/build/lib/commands/keychains.js +13 -14
  101. package/build/lib/commands/keychains.js.map +1 -1
  102. package/build/lib/commands/localization.d.ts +16 -19
  103. package/build/lib/commands/localization.d.ts.map +1 -1
  104. package/build/lib/commands/localization.js +25 -26
  105. package/build/lib/commands/localization.js.map +1 -1
  106. package/build/lib/commands/location.d.ts +36 -39
  107. package/build/lib/commands/location.d.ts.map +1 -1
  108. package/build/lib/commands/location.js +99 -98
  109. package/build/lib/commands/location.js.map +1 -1
  110. package/build/lib/commands/lock.d.ts +21 -24
  111. package/build/lib/commands/lock.d.ts.map +1 -1
  112. package/build/lib/commands/lock.js +39 -38
  113. package/build/lib/commands/lock.js.map +1 -1
  114. package/build/lib/commands/log.d.ts +43 -37
  115. package/build/lib/commands/log.d.ts.map +1 -1
  116. package/build/lib/commands/log.js +174 -171
  117. package/build/lib/commands/log.js.map +1 -1
  118. package/build/lib/commands/memory.d.ts +9 -12
  119. package/build/lib/commands/memory.d.ts.map +1 -1
  120. package/build/lib/commands/memory.js +37 -39
  121. package/build/lib/commands/memory.js.map +1 -1
  122. package/build/lib/commands/navigation.d.ts +30 -33
  123. package/build/lib/commands/navigation.d.ts.map +1 -1
  124. package/build/lib/commands/navigation.js +92 -92
  125. package/build/lib/commands/navigation.js.map +1 -1
  126. package/build/lib/commands/notifications.d.ts +26 -29
  127. package/build/lib/commands/notifications.d.ts.map +1 -1
  128. package/build/lib/commands/notifications.js +53 -53
  129. package/build/lib/commands/notifications.js.map +1 -1
  130. package/build/lib/commands/pasteboard.d.ts +21 -24
  131. package/build/lib/commands/pasteboard.d.ts.map +1 -1
  132. package/build/lib/commands/pasteboard.js +37 -37
  133. package/build/lib/commands/pasteboard.js.map +1 -1
  134. package/build/lib/commands/pcap.d.ts +39 -26
  135. package/build/lib/commands/pcap.d.ts.map +1 -1
  136. package/build/lib/commands/pcap.js +81 -81
  137. package/build/lib/commands/pcap.js.map +1 -1
  138. package/build/lib/commands/performance.d.ts +63 -44
  139. package/build/lib/commands/performance.d.ts.map +1 -1
  140. package/build/lib/commands/performance.js +105 -105
  141. package/build/lib/commands/performance.js.map +1 -1
  142. package/build/lib/commands/permissions.d.ts +33 -36
  143. package/build/lib/commands/permissions.d.ts.map +1 -1
  144. package/build/lib/commands/permissions.js +66 -65
  145. package/build/lib/commands/permissions.js.map +1 -1
  146. package/build/lib/commands/proxy-helper.d.ts +12 -15
  147. package/build/lib/commands/proxy-helper.d.ts.map +1 -1
  148. package/build/lib/commands/proxy-helper.js +53 -54
  149. package/build/lib/commands/proxy-helper.js.map +1 -1
  150. package/build/lib/commands/record-audio.d.ts +49 -29
  151. package/build/lib/commands/record-audio.d.ts.map +1 -1
  152. package/build/lib/commands/record-audio.js +100 -104
  153. package/build/lib/commands/record-audio.js.map +1 -1
  154. package/build/lib/commands/recordscreen.d.ts +54 -18
  155. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  156. package/build/lib/commands/recordscreen.js +127 -129
  157. package/build/lib/commands/recordscreen.js.map +1 -1
  158. package/build/lib/commands/screenshots.d.ts +14 -17
  159. package/build/lib/commands/screenshots.d.ts.map +1 -1
  160. package/build/lib/commands/screenshots.js +108 -107
  161. package/build/lib/commands/screenshots.js.map +1 -1
  162. package/build/lib/commands/simctl.d.ts +11 -14
  163. package/build/lib/commands/simctl.d.ts.map +1 -1
  164. package/build/lib/commands/simctl.js +23 -26
  165. package/build/lib/commands/simctl.js.map +1 -1
  166. package/build/lib/commands/source.d.ts +14 -17
  167. package/build/lib/commands/source.d.ts.map +1 -1
  168. package/build/lib/commands/source.js +40 -43
  169. package/build/lib/commands/source.js.map +1 -1
  170. package/build/lib/commands/timeouts.d.ts +44 -33
  171. package/build/lib/commands/timeouts.d.ts.map +1 -1
  172. package/build/lib/commands/timeouts.js +65 -63
  173. package/build/lib/commands/timeouts.js.map +1 -1
  174. package/build/lib/commands/web.d.ts +247 -197
  175. package/build/lib/commands/web.d.ts.map +1 -1
  176. package/build/lib/commands/web.js +815 -786
  177. package/build/lib/commands/web.js.map +1 -1
  178. package/build/lib/commands/xctest-record-screen.d.ts +63 -66
  179. package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
  180. package/build/lib/commands/xctest-record-screen.js +103 -102
  181. package/build/lib/commands/xctest-record-screen.js.map +1 -1
  182. package/build/lib/commands/xctest.d.ts +55 -51
  183. package/build/lib/commands/xctest.d.ts.map +1 -1
  184. package/build/lib/commands/xctest.js +116 -117
  185. package/build/lib/commands/xctest.js.map +1 -1
  186. package/build/lib/driver.d.ts +278 -1597
  187. package/build/lib/driver.d.ts.map +1 -1
  188. package/build/lib/driver.js +320 -236
  189. package/build/lib/driver.js.map +1 -1
  190. package/build/lib/execute-method-map.d.ts.map +1 -1
  191. package/build/lib/execute-method-map.js +9 -0
  192. package/build/lib/execute-method-map.js.map +1 -1
  193. package/build/lib/real-device.d.ts +1 -1
  194. package/build/lib/real-device.d.ts.map +1 -1
  195. package/build/lib/real-device.js +2 -2
  196. package/build/lib/real-device.js.map +1 -1
  197. package/lib/commands/active-app-info.js +12 -0
  198. package/lib/commands/alert.js +68 -65
  199. package/lib/commands/app-management.js +308 -301
  200. package/lib/commands/app-strings.js +24 -26
  201. package/lib/commands/appearance.js +54 -56
  202. package/lib/commands/audit.js +18 -20
  203. package/lib/commands/battery.js +35 -37
  204. package/lib/commands/biometric.js +44 -46
  205. package/lib/commands/certificate.js +226 -215
  206. package/lib/commands/clipboard.js +30 -32
  207. package/lib/commands/condition.js +98 -100
  208. package/lib/commands/content-size.js +36 -38
  209. package/lib/commands/context.js +495 -490
  210. package/lib/commands/deviceInfo.js +19 -20
  211. package/lib/commands/element.js +367 -357
  212. package/lib/commands/execute.js +72 -72
  213. package/lib/commands/file-movement.js +132 -134
  214. package/lib/commands/find.js +160 -159
  215. package/lib/commands/general.js +238 -231
  216. package/lib/commands/geolocation.js +6 -14
  217. package/lib/commands/gesture.js +525 -515
  218. package/lib/commands/increase-contrast.js +30 -32
  219. package/lib/commands/iohid.js +32 -34
  220. package/lib/commands/keyboard.js +49 -51
  221. package/lib/commands/keychains.js +12 -14
  222. package/lib/commands/localization.js +24 -26
  223. package/lib/commands/location.js +102 -104
  224. package/lib/commands/lock.js +38 -38
  225. package/lib/commands/log.js +197 -198
  226. package/lib/commands/memory.js +40 -43
  227. package/lib/commands/navigation.js +96 -100
  228. package/lib/commands/notifications.js +57 -59
  229. package/lib/commands/pasteboard.js +37 -39
  230. package/lib/commands/pcap.js +84 -86
  231. package/lib/commands/performance.js +132 -133
  232. package/lib/commands/permissions.js +67 -69
  233. package/lib/commands/proxy-helper.js +60 -61
  234. package/lib/commands/record-audio.js +115 -120
  235. package/lib/commands/recordscreen.js +145 -149
  236. package/lib/commands/screenshots.js +116 -116
  237. package/lib/commands/simctl.js +25 -29
  238. package/lib/commands/source.js +42 -46
  239. package/lib/commands/timeouts.js +59 -63
  240. package/lib/commands/web.js +878 -858
  241. package/lib/commands/xctest-record-screen.js +103 -105
  242. package/lib/commands/xctest.js +134 -139
  243. package/lib/driver.js +288 -236
  244. package/lib/execute-method-map.ts +9 -0
  245. package/lib/real-device.js +2 -2
  246. package/npm-shrinkwrap.json +440 -76
  247. package/package.json +2 -1
  248. package/build/lib/commands/activeAppInfo.d.ts +0 -12
  249. package/build/lib/commands/activeAppInfo.d.ts.map +0 -1
  250. package/build/lib/commands/activeAppInfo.js +0 -15
  251. package/build/lib/commands/activeAppInfo.js.map +0 -1
  252. package/build/lib/commands/index.d.ts +0 -96
  253. package/build/lib/commands/index.d.ts.map +0 -1
  254. package/build/lib/commands/index.js +0 -100
  255. package/build/lib/commands/index.js.map +0 -1
  256. package/build/lib/real-device-clients/devicectl.d.ts +0 -204
  257. package/build/lib/real-device-clients/devicectl.d.ts.map +0 -1
  258. package/build/lib/real-device-clients/devicectl.js +0 -264
  259. package/build/lib/real-device-clients/devicectl.js.map +0 -1
  260. package/lib/commands/activeAppInfo.js +0 -14
  261. package/lib/commands/index.js +0 -95
  262. package/lib/real-device-clients/devicectl.js +0 -291
@@ -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