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.
Files changed (252) hide show
  1. package/CHANGELOG.md +6 -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 -38
  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 +319 -235
  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/lib/commands/active-app-info.js +12 -0
  194. package/lib/commands/alert.js +68 -65
  195. package/lib/commands/app-management.js +308 -301
  196. package/lib/commands/app-strings.js +24 -26
  197. package/lib/commands/appearance.js +54 -56
  198. package/lib/commands/audit.js +18 -20
  199. package/lib/commands/battery.js +35 -37
  200. package/lib/commands/biometric.js +44 -46
  201. package/lib/commands/certificate.js +226 -215
  202. package/lib/commands/clipboard.js +30 -32
  203. package/lib/commands/condition.js +98 -100
  204. package/lib/commands/content-size.js +36 -38
  205. package/lib/commands/context.js +495 -490
  206. package/lib/commands/deviceInfo.js +19 -20
  207. package/lib/commands/element.js +367 -357
  208. package/lib/commands/execute.js +72 -72
  209. package/lib/commands/file-movement.js +132 -134
  210. package/lib/commands/find.js +160 -159
  211. package/lib/commands/general.js +238 -231
  212. package/lib/commands/geolocation.js +6 -14
  213. package/lib/commands/gesture.js +525 -515
  214. package/lib/commands/increase-contrast.js +30 -32
  215. package/lib/commands/iohid.js +32 -34
  216. package/lib/commands/keyboard.js +49 -51
  217. package/lib/commands/keychains.js +12 -14
  218. package/lib/commands/localization.js +24 -26
  219. package/lib/commands/location.js +102 -104
  220. package/lib/commands/lock.js +38 -38
  221. package/lib/commands/log.js +197 -198
  222. package/lib/commands/memory.js +40 -42
  223. package/lib/commands/navigation.js +96 -100
  224. package/lib/commands/notifications.js +57 -59
  225. package/lib/commands/pasteboard.js +37 -39
  226. package/lib/commands/pcap.js +84 -86
  227. package/lib/commands/performance.js +132 -133
  228. package/lib/commands/permissions.js +67 -69
  229. package/lib/commands/proxy-helper.js +60 -61
  230. package/lib/commands/record-audio.js +115 -120
  231. package/lib/commands/recordscreen.js +145 -149
  232. package/lib/commands/screenshots.js +116 -116
  233. package/lib/commands/simctl.js +25 -29
  234. package/lib/commands/source.js +42 -46
  235. package/lib/commands/timeouts.js +59 -63
  236. package/lib/commands/web.js +878 -858
  237. package/lib/commands/xctest-record-screen.js +103 -105
  238. package/lib/commands/xctest.js +134 -139
  239. package/lib/driver.js +287 -235
  240. package/lib/execute-method-map.ts +9 -0
  241. package/npm-shrinkwrap.json +2 -2
  242. package/package.json +1 -1
  243. package/build/lib/commands/activeAppInfo.d.ts +0 -12
  244. package/build/lib/commands/activeAppInfo.d.ts.map +0 -1
  245. package/build/lib/commands/activeAppInfo.js +0 -15
  246. package/build/lib/commands/activeAppInfo.js.map +0 -1
  247. package/build/lib/commands/index.d.ts +0 -96
  248. package/build/lib/commands/index.d.ts.map +0 -1
  249. package/build/lib/commands/index.js +0 -100
  250. package/build/lib/commands/index.js.map +0 -1
  251. package/lib/commands/activeAppInfo.js +0 -14
  252. package/lib/commands/index.js +0 -95
@@ -21,6 +21,138 @@ const DEFAULT_PID = 'current';
21
21
  const INSTRUMENTS = 'instruments';
22
22
  const XCTRACE = 'xctrace';
23
23
 
24
+ /**
25
+ * Starts performance profiling for the device under test.
26
+ *
27
+ * Relaxing security is mandatory for simulators. It can always work for real devices.
28
+ *
29
+ * Since XCode 12 the method tries to use `xctrace` tool to record performance stats.
30
+ *
31
+ * The `instruments` developer utility is used as a fallback for this purpose if `xctrace` is not available.
32
+ *
33
+ * It is possible to record multiple profiles at the same time.
34
+ *
35
+ * Read [Recording, Pausing, and Stopping Traces](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Recording,Pausing,andStoppingTraces.html) for more details.
36
+ *
37
+ * @param {number} timeout - The maximum count of milliseconds to record the profiling information.
38
+ * @param {string} profileName - The name of existing performance profile to apply. Can also contain the full path to the chosen template on the server file system. Note: not all profiles are supported on mobile devices.
39
+ * @param {number|'current'} [pid] - The ID of the process to measure the performance for. Set it to `current` in order to measure the performance of the process, which belongs to the currently active application. All processes running on the device are measured if `pid` is unset (the default setting).
40
+ * @this {XCUITestDriver}
41
+ */
42
+ export async function mobileStartPerfRecord(
43
+ timeout = DEFAULT_TIMEOUT_MS,
44
+ profileName = DEFAULT_PROFILE_NAME,
45
+ pid,
46
+ ) {
47
+ if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
48
+ throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
49
+ }
50
+
51
+ if (!_.isEmpty(this._perfRecorders)) {
52
+ for (const recorder of this._perfRecorders.filter((x) => x.profileName === profileName)) {
53
+ if (recorder.isRunning()) {
54
+ this.log.debug(
55
+ `Performance recorder for '${profileName}' on device '${this.device.udid}' ` +
56
+ ` is already running. Doing nothing`,
57
+ );
58
+ return;
59
+ }
60
+ _.pull(this._perfRecorders, recorder);
61
+ await recorder.stop(true);
62
+ }
63
+ }
64
+
65
+ let realPid;
66
+ if (pid) {
67
+ if (_.toLower(String(pid)) === DEFAULT_PID) {
68
+ const appInfo = /** @type {import('./types').ActiveAppInfo} */ (
69
+ await this.proxyCommand('/wda/activeAppInfo', 'GET')
70
+ );
71
+ realPid = appInfo.pid;
72
+ } else {
73
+ realPid = pid;
74
+ }
75
+ }
76
+ const recorder = new PerfRecorder(await tempDir.openDir(), this.device.udid, {
77
+ timeout: parseInt(String(timeout), 10),
78
+ profileName,
79
+ pid: parseInt(String(realPid), 10),
80
+ });
81
+ await recorder.start();
82
+ this._perfRecorders = [...(this._perfRecorders || []), recorder];
83
+ }
84
+
85
+ /**
86
+ * Stops performance recording operation previously started by {@linkcode XCUITestDriver.mobileStartPerfRecord mobile: startPerfRecord}.
87
+ *
88
+ * If the previous call has already been completed due to the timeout, then its result is returned immediately. An error is thrown if the performance recording failed to start.
89
+ *
90
+ * The resulting file in `.trace` format can be either returned directly as base64-encoded zip archive or uploaded to a remote location (such files can be pretty large). Afterwards it is possible to unarchive and open such files with Xcode Dev Tools.
91
+ *
92
+ * @param {string} [remotePath] - The path to the remote location, where the resulting zipped `.trace` file should be uploaded. The following protocols are supported: `http`, `https`, `ftp`. Null or empty string value (the default setting) means the content of resulting file should be zipped, encoded as Base64 and passed as the endpoint response value. An exception will be thrown if the generated file is too big to fit into the available process memory.
93
+ * @param {string} [user] - The name of the user for the remote authentication. Only works if `remotePath` is provided.
94
+ * @param {string} [pass] - The password for the remote authentication. Only works if `remotePath` is provided.
95
+ * @param {import('axios').Method} [method] - The http multipart upload method name. Only works if `remotePath` is provided. Defaults to `PUT`
96
+ * @param {string} profileName - The name of existing performance profile to stop the recording for. Multiple recorders for different profile names could be executed at the same time.
97
+ * @param {Record<string,any>} [headers] - Additional headers mapping for multipart http(s) uploads
98
+ * @param {string} [fileFieldName] - The name of the form field, where the file content BLOB should be stored for http(s) uploads. Defaults to `file`
99
+ * @param {Record<string,any>|([string, any])[]} [formFields] - Additional form fields for multipart http(s) uploads
100
+ *
101
+ * @returns {Promise<string>} The resulting file in `.trace` format. This file can either be returned directly as base64-encoded `.zip` archive or uploaded to a remote location (note that such files may be large), _depending on the `remotePath` argument value._ Thereafter, the file may be unarchived and opened with Xcode Developer Tools.
102
+ * @throws {Error} If no performance recording with given profile name/device udid combination
103
+ * has been started before or the resulting .trace file has not been generated properly.
104
+ * @this {XCUITestDriver}
105
+ */
106
+ export async function mobileStopPerfRecord(
107
+ remotePath,
108
+ user,
109
+ pass,
110
+ method,
111
+ profileName = DEFAULT_PROFILE_NAME,
112
+ headers,
113
+ fileFieldName,
114
+ formFields,
115
+ ) {
116
+ if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
117
+ throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
118
+ }
119
+
120
+ if (_.isEmpty(this._perfRecorders)) {
121
+ this.log.info('No performance recorders have been started. Doing nothing');
122
+ return '';
123
+ }
124
+
125
+ const recorders = this._perfRecorders.filter((x) => x.profileName === profileName);
126
+ if (_.isEmpty(recorders)) {
127
+ throw this.log.errorWithException(
128
+ `There are no records for performance profile '${profileName}' ` +
129
+ `and device ${this.device.udid}. Have you started the profiling before?`,
130
+ );
131
+ }
132
+
133
+ const recorder = _.first(recorders);
134
+ const resultPath = await /** @type {PerfRecorder} */ (recorder).stop();
135
+ if (!(await fs.exists(resultPath))) {
136
+ throw this.log.errorWithException(
137
+ `There is no ${DEFAULT_EXT} file found for performance profile '${profileName}' ` +
138
+ `and device ${this.device.udid}. Make sure the selected profile is supported on this device`,
139
+ );
140
+ }
141
+
142
+ const result = await encodeBase64OrUpload(resultPath, remotePath, {
143
+ user,
144
+ pass,
145
+ method,
146
+ headers,
147
+ fileFieldName,
148
+ formFields,
149
+ });
150
+ _.pull(this._perfRecorders, recorder);
151
+ await fs.rimraf(resultPath);
152
+ return result;
153
+ }
154
+
155
+
24
156
  async function requireXctrace() {
25
157
  const xcrunPath = await requireXcrun();
26
158
  try {
@@ -255,139 +387,6 @@ export class PerfRecorder {
255
387
  }
256
388
  }
257
389
 
258
- export default {
259
- /**
260
- * Starts performance profiling for the device under test.
261
- *
262
- * Relaxing security is mandatory for simulators. It can always work for real devices.
263
- *
264
- * Since XCode 12 the method tries to use `xctrace` tool to record performance stats.
265
- *
266
- * The `instruments` developer utility is used as a fallback for this purpose if `xctrace` is not available.
267
- *
268
- * It is possible to record multiple profiles at the same time.
269
- *
270
- * Read [Recording, Pausing, and Stopping Traces](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Recording,Pausing,andStoppingTraces.html) for more details.
271
- *
272
- * @param {number} timeout - The maximum count of milliseconds to record the profiling information.
273
- * @param {string} profileName - The name of existing performance profile to apply. Can also contain the full path to the chosen template on the server file system. Note: not all profiles are supported on mobile devices.
274
- * @param {number|'current'} [pid] - The ID of the process to measure the performance for. Set it to `current` in order to measure the performance of the process, which belongs to the currently active application. All processes running on the device are measured if `pid` is unset (the default setting).
275
- * @this {XCUITestDriver}
276
- */
277
- async mobileStartPerfRecord(
278
- timeout = DEFAULT_TIMEOUT_MS,
279
- profileName = DEFAULT_PROFILE_NAME,
280
- pid,
281
- ) {
282
- if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
283
- throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
284
- }
285
-
286
- if (!_.isEmpty(this._perfRecorders)) {
287
- for (const recorder of this._perfRecorders.filter((x) => x.profileName === profileName)) {
288
- if (recorder.isRunning()) {
289
- this.log.debug(
290
- `Performance recorder for '${profileName}' on device '${this.device.udid}' ` +
291
- ` is already running. Doing nothing`,
292
- );
293
- return;
294
- }
295
- _.pull(this._perfRecorders, recorder);
296
- await recorder.stop(true);
297
- }
298
- }
299
-
300
- let realPid;
301
- if (pid) {
302
- if (_.toLower(String(pid)) === DEFAULT_PID) {
303
- const appInfo = /** @type {import('./types').ActiveAppInfo} */ (
304
- await this.proxyCommand('/wda/activeAppInfo', 'GET')
305
- );
306
- realPid = appInfo.pid;
307
- } else {
308
- realPid = pid;
309
- }
310
- }
311
- const recorder = new PerfRecorder(await tempDir.openDir(), this.device.udid, {
312
- timeout: parseInt(String(timeout), 10),
313
- profileName,
314
- pid: parseInt(String(realPid), 10),
315
- });
316
- await recorder.start();
317
- this._perfRecorders = [...(this._perfRecorders || []), recorder];
318
- },
319
-
320
- /**
321
- * Stops performance recording operation previously started by {@linkcode XCUITestDriver.mobileStartPerfRecord mobile: startPerfRecord}.
322
- *
323
- * If the previous call has already been completed due to the timeout, then its result is returned immediately. An error is thrown if the performance recording failed to start.
324
- *
325
- * The resulting file in `.trace` format can be either returned directly as base64-encoded zip archive or uploaded to a remote location (such files can be pretty large). Afterwards it is possible to unarchive and open such files with Xcode Dev Tools.
326
- *
327
- * @param {string} [remotePath] - The path to the remote location, where the resulting zipped `.trace` file should be uploaded. The following protocols are supported: `http`, `https`, `ftp`. Null or empty string value (the default setting) means the content of resulting file should be zipped, encoded as Base64 and passed as the endpoint response value. An exception will be thrown if the generated file is too big to fit into the available process memory.
328
- * @param {string} [user] - The name of the user for the remote authentication. Only works if `remotePath` is provided.
329
- * @param {string} [pass] - The password for the remote authentication. Only works if `remotePath` is provided.
330
- * @param {import('axios').Method} [method] - The http multipart upload method name. Only works if `remotePath` is provided. Defaults to `PUT`
331
- * @param {string} profileName - The name of existing performance profile to stop the recording for. Multiple recorders for different profile names could be executed at the same time.
332
- * @param {Record<string,any>} [headers] - Additional headers mapping for multipart http(s) uploads
333
- * @param {string} [fileFieldName] - The name of the form field, where the file content BLOB should be stored for http(s) uploads. Defaults to `file`
334
- * @param {Record<string,any>|([string, any])[]} [formFields] - Additional form fields for multipart http(s) uploads
335
- *
336
- * @returns {Promise<string>} The resulting file in `.trace` format. This file can either be returned directly as base64-encoded `.zip` archive or uploaded to a remote location (note that such files may be large), _depending on the `remotePath` argument value._ Thereafter, the file may be unarchived and opened with Xcode Developer Tools.
337
- * @throws {Error} If no performance recording with given profile name/device udid combination
338
- * has been started before or the resulting .trace file has not been generated properly.
339
- * @this {XCUITestDriver}
340
- */
341
- async mobileStopPerfRecord(
342
- remotePath,
343
- user,
344
- pass,
345
- method,
346
- profileName = DEFAULT_PROFILE_NAME,
347
- headers,
348
- fileFieldName,
349
- formFields,
350
- ) {
351
- if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
352
- throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
353
- }
354
-
355
- if (_.isEmpty(this._perfRecorders)) {
356
- this.log.info('No performance recorders have been started. Doing nothing');
357
- return '';
358
- }
359
-
360
- const recorders = this._perfRecorders.filter((x) => x.profileName === profileName);
361
- if (_.isEmpty(recorders)) {
362
- throw this.log.errorWithException(
363
- `There are no records for performance profile '${profileName}' ` +
364
- `and device ${this.device.udid}. Have you started the profiling before?`,
365
- );
366
- }
367
-
368
- const recorder = _.first(recorders);
369
- const resultPath = await /** @type {PerfRecorder} */ (recorder).stop();
370
- if (!(await fs.exists(resultPath))) {
371
- throw this.log.errorWithException(
372
- `There is no ${DEFAULT_EXT} file found for performance profile '${profileName}' ` +
373
- `and device ${this.device.udid}. Make sure the selected profile is supported on this device`,
374
- );
375
- }
376
-
377
- const result = await encodeBase64OrUpload(resultPath, remotePath, {
378
- user,
379
- pass,
380
- method,
381
- headers,
382
- fileFieldName,
383
- formFields,
384
- });
385
- _.pull(this._perfRecorders, recorder);
386
- await fs.rimraf(resultPath);
387
- return result;
388
- },
389
- };
390
-
391
390
  /**
392
391
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
393
392
  */
@@ -4,83 +4,81 @@ import {assertSimulator as _assertSimulator} from '../utils';
4
4
 
5
5
  const assertSimulator = _.partial(_assertSimulator, 'Permission-related operations');
6
6
 
7
- export default {
8
- /**
9
- * Resets the given permission for the active application under test.
10
- * Works for both Simulator and real devices using Xcode SDK 11.4+
11
- *
12
- * @param {PermissionService|number} service - One of the available service names. This could also be an integer protected resource identifier; see [this list](https://developer.apple.com/documentation/xctest/xcuiprotectedresource?language=objc)
13
- * @throws {Error} If permission reset fails on the device.
14
- * @this {XCUITestDriver}
15
- */
16
- async mobileResetPermission(service) {
17
- if (!service) {
18
- throw new Error(`The 'service' option is expected to be present`);
19
- }
20
- let resource;
21
- if (_.isString(service)) {
22
- resource = PermissionService[_.toLower(service)];
23
- if (!resource) {
24
- throw new Error(
25
- `The 'service' value must be one of ` + `${JSON.stringify(_.keys(PermissionService))}`,
26
- );
27
- }
28
- } else if (_.isInteger(service)) {
29
- resource = service;
30
- } else {
7
+ /**
8
+ * Resets the given permission for the active application under test.
9
+ * Works for both Simulator and real devices using Xcode SDK 11.4+
10
+ *
11
+ * @param {PermissionService|number} service - One of the available service names. This could also be an integer protected resource identifier; see [this list](https://developer.apple.com/documentation/xctest/xcuiprotectedresource?language=objc)
12
+ * @throws {Error} If permission reset fails on the device.
13
+ * @this {XCUITestDriver}
14
+ */
15
+ export async function mobileResetPermission(service) {
16
+ if (!service) {
17
+ throw new Error(`The 'service' option is expected to be present`);
18
+ }
19
+ let resource;
20
+ if (_.isString(service)) {
21
+ resource = PermissionService[_.toLower(service)];
22
+ if (!resource) {
31
23
  throw new Error(
32
- `The 'service' value must be either a string or an integer. ` +
33
- `'${service}' is passed instead`,
24
+ `The 'service' value must be one of ` + `${JSON.stringify(_.keys(PermissionService))}`,
34
25
  );
35
26
  }
27
+ } else if (_.isInteger(service)) {
28
+ resource = service;
29
+ } else {
30
+ throw new Error(
31
+ `The 'service' value must be either a string or an integer. ` +
32
+ `'${service}' is passed instead`,
33
+ );
34
+ }
36
35
 
37
- await this.proxyCommand('/wda/resetAppAuth', 'POST', {resource});
38
- },
36
+ await this.proxyCommand('/wda/resetAppAuth', 'POST', {resource});
37
+ }
39
38
 
40
- /**
41
- * Gets application permission state on a simulated device.
42
- *
43
- * **This method requires [WIX applesimutils](https://github.com/wix/AppleSimulatorUtils) to be installed on the Appium server host.**
44
- *
45
- * @param {string} bundleId - Bundle identifier of the target application
46
- * @param {import('./enum').PermissionService} service - Service name
47
- * @returns {Promise<import('./types').PermissionState>} Either 'yes', 'no', 'unset' or 'limited'
48
- * @throws {Error} If permission getting fails or the device is not a Simulator.
49
- * @this {XCUITestDriver}
50
- * @group Simulator Only
51
- */
52
- async mobileGetPermission(bundleId, service) {
53
- if (!service) {
54
- throw new Error(`The 'service' option is expected to be present`);
55
- }
56
- assertSimulator(this);
39
+ /**
40
+ * Gets application permission state on a simulated device.
41
+ *
42
+ * **This method requires [WIX applesimutils](https://github.com/wix/AppleSimulatorUtils) to be installed on the Appium server host.**
43
+ *
44
+ * @param {string} bundleId - Bundle identifier of the target application
45
+ * @param {import('./enum').PermissionService} service - Service name
46
+ * @returns {Promise<import('./types').PermissionState>} Either 'yes', 'no', 'unset' or 'limited'
47
+ * @throws {Error} If permission getting fails or the device is not a Simulator.
48
+ * @this {XCUITestDriver}
49
+ * @group Simulator Only
50
+ */
51
+ export async function mobileGetPermission(bundleId, service) {
52
+ if (!service) {
53
+ throw new Error(`The 'service' option is expected to be present`);
54
+ }
55
+ assertSimulator(this);
57
56
 
58
- return /** @type {import('./types').PermissionState} */ (
59
- await /** @type {import('../driver').Simulator} */ (this.device).getPermission(
60
- bundleId, String(service)
61
- )
62
- );
63
- },
57
+ return /** @type {import('./types').PermissionState} */ (
58
+ await /** @type {import('../driver').Simulator} */ (this.device).getPermission(
59
+ bundleId, String(service)
60
+ )
61
+ );
62
+ }
64
63
 
65
- /**
66
- * Set application permission state on Simulator.
67
- *
68
- * @param {Record<Partial<import('./types').AccessRule>, import('./types').PermissionState>} access - One or more access rules to set.
69
- * @param {string} bundleId - Bundle identifier of the target application
70
- * @since Xcode SDK 11.4
71
- * @throws {Error} If permission setting fails or the device is not a Simulator.
72
- * @group Simulator Only
73
- * @this {XCUITestDriver}
74
- */
75
- async mobileSetPermissions(access, bundleId) {
76
- if (!_.isPlainObject(access)) {
77
- throw new Error(`The 'access' option is expected to be a map`);
78
- }
79
- assertSimulator(this);
64
+ /**
65
+ * Set application permission state on Simulator.
66
+ *
67
+ * @param {Record<Partial<import('./types').AccessRule>, import('./types').PermissionState>} access - One or more access rules to set.
68
+ * @param {string} bundleId - Bundle identifier of the target application
69
+ * @since Xcode SDK 11.4
70
+ * @throws {Error} If permission setting fails or the device is not a Simulator.
71
+ * @group Simulator Only
72
+ * @this {XCUITestDriver}
73
+ */
74
+ export async function mobileSetPermissions(access, bundleId) {
75
+ if (!_.isPlainObject(access)) {
76
+ throw new Error(`The 'access' option is expected to be a map`);
77
+ }
78
+ assertSimulator(this);
80
79
 
81
- await /** @type {import('../driver').Simulator} */ (this.device).setPermissions(bundleId, access);
82
- },
83
- };
80
+ await /** @type {import('../driver').Simulator} */ (this.device).setPermissions(bundleId, access);
81
+ }
84
82
 
85
83
  /**
86
84
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
@@ -46,76 +46,75 @@ const WDA_ROUTES = /** @type {const} */ ({
46
46
  });
47
47
 
48
48
  /**
49
- * @param {string} endpoint
49
+ * Proxies a command to WebDriverAgent
50
+ * @template [TReq=any]
51
+ * @template [TRes=unknown]
52
+ * @param {string} url
50
53
  * @param {AllowedHttpMethod} method
51
- * @returns {string|undefined}
54
+ * @param {TReq} [body]
55
+ * @param {boolean} isSessionCommand
56
+ * @this {import('../driver').XCUITestDriver}
57
+ * @returns {Promise<TRes>}
52
58
  */
53
- function wdaRouteToCommandName(endpoint, method) {
54
- if (endpoint in WDA_ROUTES) {
55
- return WDA_ROUTES[endpoint][method];
59
+ export async function proxyCommand(url, method, body, isSessionCommand = true) {
60
+ if (this.shutdownUnexpectedly) {
61
+ return /** @type {TRes} */ (undefined);
56
62
  }
57
- }
58
- export default {
59
- /**
60
- * Proxies a command to WebDriverAgent
61
- * @template [TReq=any]
62
- * @template [TRes=unknown]
63
- * @param {string} url
64
- * @param {AllowedHttpMethod} method
65
- * @param {TReq} [body]
66
- * @param {boolean} isSessionCommand
67
- * @this {import('../driver').XCUITestDriver}
68
- * @returns {Promise<TRes>}
69
- */
70
- async proxyCommand(url, method, body, isSessionCommand = true) {
71
- if (this.shutdownUnexpectedly) {
72
- return /** @type {TRes} */ (undefined);
73
- }
74
63
 
75
- if (!url) {
76
- throw this.log.errorWithException('Proxying requires an endpoint');
77
- } else if (!SUPPORTED_METHODS.has(method)) {
78
- throw this.log.errorWithException(
79
- `Proxying only works for the following HTTP methods: ${[...SUPPORTED_METHODS].join(', ')}`,
80
- );
81
- }
64
+ if (!url) {
65
+ throw this.log.errorWithException('Proxying requires an endpoint');
66
+ } else if (!SUPPORTED_METHODS.has(method)) {
67
+ throw this.log.errorWithException(
68
+ `Proxying only works for the following HTTP methods: ${[...SUPPORTED_METHODS].join(', ')}`,
69
+ );
70
+ }
82
71
 
83
- if (!this.wda) {
84
- throw new Error('Cannot call proxyCommand without WDA driver active');
85
- }
86
- const proxy = isSessionCommand ? this.wda.jwproxy : this.wda.noSessionProxy;
87
- if (!proxy) {
88
- throw new Error('Cannot call proxyCommand without WDA proxy active');
89
- }
72
+ if (!this.wda) {
73
+ throw new Error('Cannot call proxyCommand without WDA driver active');
74
+ }
75
+ const proxy = isSessionCommand ? this.wda.jwproxy : this.wda.noSessionProxy;
76
+ if (!proxy) {
77
+ throw new Error('Cannot call proxyCommand without WDA proxy active');
78
+ }
90
79
 
91
- let cmdName = wdaRouteToCommandName(url, method) || routeToCommandName(url, method);
92
- const timeout = this._getCommandTimeout(cmdName);
93
- if (!cmdName) {
94
- // this should never happen except when adding new routes
95
- cmdName = 'Unknown'; // just for logging purposes below
96
- this.log.info(`Proxying to WDA with an unknown route: ${method} ${url}`);
97
- }
80
+ let cmdName = wdaRouteToCommandName(url, method) || routeToCommandName(url, method);
81
+ const timeout = this._getCommandTimeout(cmdName);
82
+ if (!cmdName) {
83
+ // this should never happen except when adding new routes
84
+ cmdName = 'Unknown'; // just for logging purposes below
85
+ this.log.info(`Proxying to WDA with an unknown route: ${method} ${url}`);
86
+ }
98
87
 
99
- if (!timeout) {
100
- return /** @type {TRes} */ (await proxy.command(url, method, body));
101
- }
88
+ if (!timeout) {
89
+ return /** @type {TRes} */ (await proxy.command(url, method, body));
90
+ }
102
91
 
103
- this.log.debug(`Setting custom timeout to ${timeout} ms for '${cmdName}' command`);
104
- try {
105
- return /** @type {TRes} */ (await B.resolve(proxy.command(url, method, body)).timeout(timeout));
106
- } catch (e) {
107
- if (!(e instanceof B.Promise.TimeoutError)) {
108
- throw e;
109
- }
110
- proxy.cancelActiveRequests();
111
- const error = new errors.TimeoutError(
112
- `Appium did not get any response from '${cmdName}' command in ${timeout} ms`
113
- );
114
- await this.startUnexpectedShutdown(error);
115
- throw error;
92
+ this.log.debug(`Setting custom timeout to ${timeout} ms for '${cmdName}' command`);
93
+ try {
94
+ return /** @type {TRes} */ (await B.resolve(proxy.command(url, method, body)).timeout(timeout));
95
+ } catch (e) {
96
+ if (!(e instanceof B.Promise.TimeoutError)) {
97
+ throw e;
116
98
  }
117
- },
118
- };
99
+ proxy.cancelActiveRequests();
100
+ const error = new errors.TimeoutError(
101
+ `Appium did not get any response from '${cmdName}' command in ${timeout} ms`
102
+ );
103
+ await this.startUnexpectedShutdown(error);
104
+ throw error;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * @param {string} endpoint
110
+ * @param {AllowedHttpMethod} method
111
+ * @returns {string|undefined}
112
+ */
113
+ function wdaRouteToCommandName(endpoint, method) {
114
+ if (endpoint in WDA_ROUTES) {
115
+ return WDA_ROUTES[endpoint][method];
116
+ }
117
+ }
119
118
 
120
119
  /**
121
120
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver