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
@@ -1,45 +1,45 @@
1
1
  import B from 'bluebird';
2
2
 
3
- export default {
4
- /**
5
- * Lock the device (and optionally unlock the device after a certain amount of time)
6
- *
7
- * @param {number|string} [seconds] - the number of seconds after which to unlock the device. Set to `0` or leave empty to require manual unlock (do not automatically unlock).
8
- * @defaultValue 0
9
- * @this {XCUITestDriver}
10
- */
11
- async lock(seconds) {
12
- await this.proxyCommand('/wda/lock', 'POST');
13
- if (isNaN(Number(seconds))) {
14
- return;
15
- }
3
+ /**
4
+ * Lock the device (and optionally unlock the device after a certain amount of time)
5
+ *
6
+ * @param {number|string} [seconds] - the number of seconds after which to unlock the device. Set to `0` or leave empty to require manual unlock (do not automatically unlock).
7
+ * @defaultValue 0
8
+ * @this {XCUITestDriver}
9
+ */
10
+ export async function lock(seconds) {
11
+ await this.proxyCommand('/wda/lock', 'POST');
12
+ if (isNaN(Number(seconds))) {
13
+ return;
14
+ }
15
+
16
+ const floatSeconds = parseFloat(String(seconds));
17
+ if (floatSeconds <= 0) {
18
+ return;
19
+ }
20
+
21
+ await B.delay(floatSeconds * 1000);
22
+ await this.proxyCommand('/wda/unlock', 'POST');
23
+ }
16
24
 
17
- const floatSeconds = parseFloat(String(seconds));
18
- if (floatSeconds <= 0) {
19
- return;
20
- }
25
+ /**
26
+ * Unlock the device
27
+ *
28
+ * @this {XCUITestDriver}
29
+ */
30
+ export async function unlock() {
31
+ await this.proxyCommand('/wda/unlock', 'POST');
32
+ }
21
33
 
22
- await B.delay(floatSeconds * 1000);
23
- await this.proxyCommand('/wda/unlock', 'POST');
24
- },
25
- /**
26
- * Unlock the device
27
- *
28
- * @this {XCUITestDriver}
29
- */
30
- async unlock() {
31
- await this.proxyCommand('/wda/unlock', 'POST');
32
- },
33
- /**
34
- * Determine whether the device is locked
35
- *
36
- * @this {XCUITestDriver}
37
- * @returns {Promise<boolean>} `true` if the device is locked, `false` otherwise
38
- */
39
- async isLocked() {
40
- return /** @type {boolean} */ (await this.proxyCommand('/wda/locked', 'GET'));
41
- },
42
- };
34
+ /**
35
+ * Determine whether the device is locked
36
+ *
37
+ * @this {XCUITestDriver}
38
+ * @returns {Promise<boolean>} `true` if the device is locked, `false` otherwise
39
+ */
40
+ export async function isLocked() {
41
+ return /** @type {boolean} */ (await this.proxyCommand('/wda/locked', 'GET'));
42
+ }
43
43
 
44
44
  /**
45
45
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
@@ -22,19 +22,6 @@ const WEBSOCKET_ENDPOINT = (sessionId) =>
22
22
  const COLOR_CODE_PATTERN = /\u001b\[(\d+(;\d+)*)?m/g; // eslint-disable-line no-control-regex
23
23
  const GET_SERVER_LOGS_FEATURE = 'get_server_logs';
24
24
 
25
- /**
26
- *
27
- * @param {Object} x
28
- * @returns {import('./types').LogEntry}
29
- */
30
- function nativeLogEntryToSeleniumEntry (x) {
31
- const msg = _.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
32
- return toLogEntry(
33
- _.replace(msg, COLOR_CODE_PATTERN, ''),
34
- /** @type {any} */ (x).timestamp ?? Date.now()
35
- );
36
- }
37
-
38
25
  /**
39
26
  * @type {import('@appium/types').LogDefRecord}
40
27
  * @privateRemarks The return types for these getters should be specified
@@ -78,216 +65,215 @@ const LOG_NAMES_TO_CAPABILITY_NAMES_MAP = {
78
65
  enablePerformanceLogging: 'enablePerformanceLogging',
79
66
  };
80
67
 
81
- export default {
82
- supportedLogTypes: SUPPORTED_LOG_TYPES,
83
- /**
84
- *
85
- * @param {XCUITestDriverLogTypes} logType
86
- * @param {Partial<Record<XCUITestDriverLogTypes,{getLogs(): Promise<any>}>>} [logsContainer]
87
- * @this {XCUITestDriver}
88
- */
89
- async extractLogs(logType, logsContainer = {}) {
90
- // make sure that we have logs at all
91
- // otherwise it's not been initialized
92
- if (_.isEmpty(logsContainer)) {
93
- throw new Error('No logs currently available. Is the device/simulator started?');
94
- }
68
+ export const supportedLogTypes = SUPPORTED_LOG_TYPES;
95
69
 
96
- // If logs captured successfully send response with data, else send error
97
- const logObject = logsContainer[logType];
98
- if (logObject) {
99
- return await logObject.getLogs();
100
- }
101
- if (logType in LOG_NAMES_TO_CAPABILITY_NAMES_MAP) {
102
- throw new Error(
103
- `${logType} logs are not enabled. Make sure you've set a proper value ` +
104
- `to the 'appium:${LOG_NAMES_TO_CAPABILITY_NAMES_MAP[logType]}' capability.`
105
- );
106
- }
70
+ /**
71
+ *
72
+ * @param {XCUITestDriverLogTypes} logType
73
+ * @param {Partial<Record<XCUITestDriverLogTypes,{getLogs(): Promise<any>}>>} [logsContainer]
74
+ * @this {XCUITestDriver}
75
+ */
76
+ export async function extractLogs(logType, logsContainer = {}) {
77
+ // make sure that we have logs at all
78
+ // otherwise it's not been initialized
79
+ if (_.isEmpty(logsContainer)) {
80
+ throw new Error('No logs currently available. Is the device/simulator started?');
81
+ }
82
+
83
+ // If logs captured successfully send response with data, else send error
84
+ const logObject = logsContainer[logType];
85
+ if (logObject) {
86
+ return await logObject.getLogs();
87
+ }
88
+ if (logType in LOG_NAMES_TO_CAPABILITY_NAMES_MAP) {
107
89
  throw new Error(
108
- `No logs of type '${logType}' found. Supported log types are: ${_.keys(SUPPORTED_LOG_TYPES)}.`
90
+ `${logType} logs are not enabled. Make sure you've set a proper value ` +
91
+ `to the 'appium:${LOG_NAMES_TO_CAPABILITY_NAMES_MAP[logType]}' capability.`
109
92
  );
110
- },
93
+ }
94
+ throw new Error(
95
+ `No logs of type '${logType}' found. Supported log types are: ${_.keys(SUPPORTED_LOG_TYPES)}.`
96
+ );
97
+ }
111
98
 
112
- /**
113
- * @this {XCUITestDriver}
114
- */
115
- async startLogCapture() {
116
- this.logs = this.logs || {};
117
- if (!_.isUndefined(this.logs.syslog) && this.logs.syslog.isCapturing) {
118
- this.log.warn('Trying to start iOS log capture but it has already started!');
119
- return true;
120
- }
99
+ /**
100
+ * @this {XCUITestDriver}
101
+ */
102
+ export async function startLogCapture() {
103
+ this.logs = this.logs || {};
104
+ if (!_.isUndefined(this.logs.syslog) && this.logs.syslog.isCapturing) {
105
+ this.log.warn('Trying to start iOS log capture but it has already started!');
106
+ return true;
107
+ }
121
108
 
122
- if (_.isUndefined(this.logs.syslog)) {
123
- [this.logs.crashlog,] = assignBiDiLogListener.bind(this)(
124
- new IOSCrashLog({
109
+ if (_.isUndefined(this.logs.syslog)) {
110
+ [this.logs.crashlog,] = assignBiDiLogListener.bind(this)(
111
+ new IOSCrashLog({
112
+ sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
113
+ udid: this.isRealDevice() ? this.opts.udid : undefined,
114
+ log: this.log,
115
+ }), {
116
+ type: 'crashlog',
117
+ }
118
+ );
119
+ [this.logs.syslog,] = assignBiDiLogListener.bind(this)(
120
+ this.isRealDevice()
121
+ ? new IOSDeviceLog({
122
+ udid: this.opts.udid,
123
+ showLogs: this.opts.showIOSLog,
124
+ log: this.log,
125
+ })
126
+ : new IOSSimulatorLog({
125
127
  sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
126
- udid: this.isRealDevice() ? this.opts.udid : undefined,
128
+ showLogs: this.opts.showIOSLog,
129
+ iosSimulatorLogsPredicate: this.opts.iosSimulatorLogsPredicate,
130
+ simulatorLogLevel: this.opts.simulatorLogLevel,
131
+ log: this.log,
132
+ iosSyslogFile: this.opts.iosSyslogFile
133
+ }),
134
+ {
135
+ type: 'syslog',
136
+ }
137
+ );
138
+ if (_.isBoolean(this.opts.showSafariConsoleLog)) {
139
+ [this.logs.safariConsole,] = assignBiDiLogListener.bind(this)(
140
+ new SafariConsoleLog({
141
+ showLogs: this.opts.showSafariConsoleLog,
127
142
  log: this.log,
128
143
  }), {
129
- type: 'crashlog',
144
+ type: 'safariConsole',
130
145
  }
131
146
  );
132
- [this.logs.syslog,] = assignBiDiLogListener.bind(this)(
133
- this.isRealDevice()
134
- ? new IOSDeviceLog({
135
- udid: this.opts.udid,
136
- showLogs: this.opts.showIOSLog,
137
- log: this.log,
138
- })
139
- : new IOSSimulatorLog({
140
- sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
141
- showLogs: this.opts.showIOSLog,
142
- iosSimulatorLogsPredicate: this.opts.iosSimulatorLogsPredicate,
143
- simulatorLogLevel: this.opts.simulatorLogLevel,
144
- log: this.log,
145
- iosSyslogFile: this.opts.iosSyslogFile
146
- }),
147
- {
148
- type: 'syslog',
147
+ }
148
+ if (_.isBoolean(this.opts.showSafariNetworkLog)) {
149
+ [this.logs.safariNetwork,] = assignBiDiLogListener.bind(this)(
150
+ new SafariNetworkLog({
151
+ showLogs: this.opts.showSafariNetworkLog,
152
+ log: this.log,
153
+ }), {
154
+ type: 'safariNetwork',
149
155
  }
150
156
  );
151
- if (_.isBoolean(this.opts.showSafariConsoleLog)) {
152
- [this.logs.safariConsole,] = assignBiDiLogListener.bind(this)(
153
- new SafariConsoleLog({
154
- showLogs: this.opts.showSafariConsoleLog,
155
- log: this.log,
156
- }), {
157
- type: 'safariConsole',
158
- }
159
- );
160
- }
161
- if (_.isBoolean(this.opts.showSafariNetworkLog)) {
162
- [this.logs.safariNetwork,] = assignBiDiLogListener.bind(this)(
163
- new SafariNetworkLog({
164
- showLogs: this.opts.showSafariNetworkLog,
165
- log: this.log,
166
- }), {
167
- type: 'safariNetwork',
168
- }
169
- );
170
- }
171
- if (this.isFeatureEnabled(GET_SERVER_LOGS_FEATURE)) {
172
- [, this._bidiServerLogListener] = assignBiDiLogListener.bind(this)(
173
- this.log.unwrap(), {
174
- type: 'server',
175
- srcEventName: 'log',
176
- entryTransformer: nativeLogEntryToSeleniumEntry,
177
- }
178
- );
179
- }
180
157
  }
181
-
182
- let didStartSyslog = false;
183
- /** @type {Promise[]} */
184
- const promises = [
185
- (async () => {
186
- try {
187
- await this.logs.syslog?.startCapture();
188
- didStartSyslog = true;
189
- this.eventEmitter.emit('syslogStarted', this.logs.syslog);
190
- } catch (err) {
191
- this.log.debug(err.stack);
192
- this.log.warn(`Continuing without capturing device logs: ${err.message}`);
158
+ if (this.isFeatureEnabled(GET_SERVER_LOGS_FEATURE)) {
159
+ [, this._bidiServerLogListener] = assignBiDiLogListener.bind(this)(
160
+ this.log.unwrap(), {
161
+ type: 'server',
162
+ srcEventName: 'log',
163
+ entryTransformer: nativeLogEntryToSeleniumEntry,
193
164
  }
194
- })(),
195
- this.logs.crashlog?.startCapture() ?? B.resolve(),
196
- ];
197
- await B.all(promises);
198
-
199
- return didStartSyslog;
200
- },
201
-
202
- /**
203
- * Starts an iOS system logs broadcast websocket.
204
- *
205
- * The websocket listens on the same host and port as Appium. The endpoint created is `/ws/session/:sessionId:/appium/syslog`.
206
- *
207
- * If the websocket is already running, this command does nothing.
208
- *
209
- * Each connected webcoket listener will receive syslog lines as soon as they are visible to Appium.
210
- * @see https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium
211
- * @returns {Promise<void>}
212
- * @this {XCUITestDriver}
213
- */
214
- async mobileStartLogsBroadcast() {
215
- const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
216
- if (
217
- !_.isEmpty(
218
- await /** @type {import('@appium/types').AppiumServer} */ (
219
- this.server
220
- ).getWebSocketHandlers(pathname),
221
- )
222
- ) {
223
- this.log.debug(
224
- `The system logs broadcasting web socket server is already listening at ${pathname}`,
225
165
  );
226
- return;
227
166
  }
167
+ }
228
168
 
229
- this.log.info(`Assigning system logs broadcasting web socket server to ${pathname}`);
230
- // https://github.com/websockets/ws/blob/master/doc/ws.md
231
- const wss = new WebSocket.Server({
232
- noServer: true,
233
- });
234
- wss.on('connection', (ws, req) => {
235
- if (req) {
236
- const remoteIp = _.isEmpty(req.headers['x-forwarded-for'])
237
- ? req.connection?.remoteAddress
238
- : req.headers['x-forwarded-for'];
239
- this.log.debug(`Established a new system logs listener web socket connection from ${remoteIp}`);
240
- } else {
241
- this.log.debug('Established a new system logs listener web socket connection');
169
+ let didStartSyslog = false;
170
+ /** @type {Promise[]} */
171
+ const promises = [
172
+ (async () => {
173
+ try {
174
+ await this.logs.syslog?.startCapture();
175
+ didStartSyslog = true;
176
+ this.eventEmitter.emit('syslogStarted', this.logs.syslog);
177
+ } catch (err) {
178
+ this.log.debug(err.stack);
179
+ this.log.warn(`Continuing without capturing device logs: ${err.message}`);
242
180
  }
181
+ })(),
182
+ this.logs.crashlog?.startCapture() ?? B.resolve(),
183
+ ];
184
+ await B.all(promises);
243
185
 
244
- if (_.isEmpty(this._syslogWebsocketListener)) {
245
- this._syslogWebsocketListener = (logRecord) => {
246
- if (ws?.readyState === WebSocket.OPEN) {
247
- ws.send(logRecord.message);
248
- }
249
- };
250
- }
251
- this.logs.syslog?.on('output', this._syslogWebsocketListener);
186
+ return didStartSyslog;
187
+ }
252
188
 
253
- ws.on('close', (code, reason) => {
254
- if (!_.isEmpty(this._syslogWebsocketListener)) {
255
- this.logs.syslog?.removeListener('output', this._syslogWebsocketListener);
256
- this._syslogWebsocketListener = null;
257
- }
189
+ /**
190
+ * Starts an iOS system logs broadcast websocket.
191
+ *
192
+ * The websocket listens on the same host and port as Appium. The endpoint created is `/ws/session/:sessionId:/appium/syslog`.
193
+ *
194
+ * If the websocket is already running, this command does nothing.
195
+ *
196
+ * Each connected webcoket listener will receive syslog lines as soon as they are visible to Appium.
197
+ * @see https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium
198
+ * @returns {Promise<void>}
199
+ * @this {XCUITestDriver}
200
+ */
201
+ export async function mobileStartLogsBroadcast() {
202
+ const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
203
+ if (
204
+ !_.isEmpty(
205
+ await /** @type {import('@appium/types').AppiumServer} */ (
206
+ this.server
207
+ ).getWebSocketHandlers(pathname),
208
+ )
209
+ ) {
210
+ this.log.debug(
211
+ `The system logs broadcasting web socket server is already listening at ${pathname}`,
212
+ );
213
+ return;
214
+ }
258
215
 
259
- let closeMsg = 'System logs listener web socket is closed.';
260
- if (!_.isEmpty(code)) {
261
- closeMsg += ` Code: ${code}.`;
262
- }
263
- if (!_.isEmpty(reason)) {
264
- closeMsg += ` Reason: ${reason.toString()}.`;
216
+ this.log.info(`Assigning system logs broadcasting web socket server to ${pathname}`);
217
+ // https://github.com/websockets/ws/blob/master/doc/ws.md
218
+ const wss = new WebSocket.Server({
219
+ noServer: true,
220
+ });
221
+ wss.on('connection', (ws, req) => {
222
+ if (req) {
223
+ const remoteIp = _.isEmpty(req.headers['x-forwarded-for'])
224
+ ? req.connection?.remoteAddress
225
+ : req.headers['x-forwarded-for'];
226
+ this.log.debug(`Established a new system logs listener web socket connection from ${remoteIp}`);
227
+ } else {
228
+ this.log.debug('Established a new system logs listener web socket connection');
229
+ }
230
+
231
+ if (_.isEmpty(this._syslogWebsocketListener)) {
232
+ this._syslogWebsocketListener = (logRecord) => {
233
+ if (ws?.readyState === WebSocket.OPEN) {
234
+ ws.send(logRecord.message);
265
235
  }
266
- this.log.debug(closeMsg);
267
- });
236
+ };
237
+ }
238
+ this.logs.syslog?.on('output', this._syslogWebsocketListener);
239
+
240
+ ws.on('close', (code, reason) => {
241
+ if (!_.isEmpty(this._syslogWebsocketListener)) {
242
+ this.logs.syslog?.removeListener('output', this._syslogWebsocketListener);
243
+ this._syslogWebsocketListener = null;
244
+ }
245
+
246
+ let closeMsg = 'System logs listener web socket is closed.';
247
+ if (!_.isEmpty(code)) {
248
+ closeMsg += ` Code: ${code}.`;
249
+ }
250
+ if (!_.isEmpty(reason)) {
251
+ closeMsg += ` Reason: ${reason.toString()}.`;
252
+ }
253
+ this.log.debug(closeMsg);
268
254
  });
269
- await /** @type {AppiumServer} */ (this.server).addWebSocketHandler(
270
- pathname,
271
- /** @type {import('@appium/types').WSServer} */ (wss),
272
- );
273
- },
255
+ });
256
+ await /** @type {AppiumServer} */ (this.server).addWebSocketHandler(
257
+ pathname,
258
+ /** @type {import('@appium/types').WSServer} */ (wss),
259
+ );
260
+ }
274
261
 
275
- /**
276
- * Stops the syslog broadcasting wesocket server previously started by `mobile: startLogsBroadcast`.
277
- * If no websocket server is running, this command does nothing.
278
- * @this {XCUITestDriver}
279
- * @returns {Promise<void>}
280
- */
281
- async mobileStopLogsBroadcast() {
282
- const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
283
- if (_.isEmpty(await /** @type {AppiumServer} */ (this.server).getWebSocketHandlers(pathname))) {
284
- return;
285
- }
262
+ /**
263
+ * Stops the syslog broadcasting wesocket server previously started by `mobile: startLogsBroadcast`.
264
+ * If no websocket server is running, this command does nothing.
265
+ * @this {XCUITestDriver}
266
+ * @returns {Promise<void>}
267
+ */
268
+ export async function mobileStopLogsBroadcast() {
269
+ const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
270
+ if (_.isEmpty(await /** @type {AppiumServer} */ (this.server).getWebSocketHandlers(pathname))) {
271
+ return;
272
+ }
286
273
 
287
- this.log.debug('Stopping the system logs broadcasting web socket server');
288
- await /** @type {AppiumServer} */ (this.server).removeWebSocketHandler(pathname);
289
- },
290
- };
274
+ this.log.debug('Stopping the system logs broadcasting web socket server');
275
+ await /** @type {AppiumServer} */ (this.server).removeWebSocketHandler(pathname);
276
+ }
291
277
 
292
278
  /**
293
279
  * https://w3c.github.io/webdriver-bidi/#event-log-entryAdded
@@ -313,6 +299,19 @@ export function assignBiDiLogListener (logEmitter, properties) {
313
299
  return [logEmitter, listener];
314
300
  }
315
301
 
302
+ /**
303
+ *
304
+ * @param {Object} x
305
+ * @returns {import('./types').LogEntry}
306
+ */
307
+ function nativeLogEntryToSeleniumEntry (x) {
308
+ const msg = _.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
309
+ return toLogEntry(
310
+ _.replace(msg, COLOR_CODE_PATTERN, ''),
311
+ /** @type {any} */ (x).timestamp ?? Date.now()
312
+ );
313
+ }
314
+
316
315
  /**
317
316
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
318
317
  * @typedef {keyof typeof SUPPORTED_LOG_TYPES} XCUITestDriverLogTypes
@@ -1,52 +1,50 @@
1
1
  import _ from 'lodash';
2
2
  import { errors } from 'appium/driver';
3
3
 
4
- export default {
5
- /**
6
- * Simulates Low Memory warning on the given application
7
- *
8
- * @since Xcode 15
9
- * @param {string} bundleId - The bundle identifier of the target app. The app must be running
10
- * @this {XCUITestDriver}
11
- * @throws {Error} if the app is not running or is not installed
12
- */
13
- async mobileSendMemoryWarning(bundleId) {
14
- if (!this.isRealDevice()) {
15
- throw new Error('Memory warning simulation is only supported on real devices');
16
- }
4
+ /**
5
+ * Simulates Low Memory warning on the given application
6
+ *
7
+ * @since Xcode 15
8
+ * @param {string} bundleId - The bundle identifier of the target app. The app must be running
9
+ * @this {XCUITestDriver}
10
+ * @throws {Error} if the app is not running or is not installed
11
+ */
12
+ export async function mobileSendMemoryWarning(bundleId) {
13
+ if (!this.isRealDevice()) {
14
+ throw new Error('Memory warning simulation is only supported on real devices');
15
+ }
17
16
 
18
- const device = /** @type {import('../real-device').RealDevice} */ (this.device);
17
+ const device = /** @type {import('../real-device').RealDevice} */ (this.device);
19
18
 
20
- const appInfos = await device.devicectl.listApps(bundleId);
21
- if (_.isEmpty(appInfos)) {
22
- throw new errors.InvalidArgumentError(
23
- `The application identified by ${bundleId} cannot be found on the device. Is it installed?`
24
- );
25
- }
19
+ const appInfos = await device.devicectl.listApps(bundleId);
20
+ if (_.isEmpty(appInfos)) {
21
+ throw new errors.InvalidArgumentError(
22
+ `The application identified by ${bundleId} cannot be found on the device. Is it installed?`
23
+ );
24
+ }
26
25
 
27
- // This regexp tries to match the process name of the main bundle executable.
28
- // For example, if 'url' contains something like
29
- // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/`
30
- // and the following processes might be running:
31
- // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/Target`
32
- // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/PlugIns/WidgetExtension.appex/WidgetExtension`
33
- // then we only want to match the first one.
34
- // Unfortunately devicectl does not provide more info which would
35
- // allow to connect a bundle id to a process id.
36
- const pattern = new RegExp(`^${_.escapeRegExp(appInfos[0].url)}[^/]+$`);
37
- /** @type {number[]} */
38
- const pids = (await device.devicectl.listProcesses())
39
- .filter(({executable}) => pattern.test(executable))
40
- .map(({processIdentifier}) => processIdentifier);
41
- if (_.isEmpty(pids)) {
42
- throw new errors.InvalidArgumentError(
43
- `The application identified by ${bundleId} must be running in order to simulate the Low Memory warning`
44
- );
45
- }
46
- this.log.info(`Emulating Low Memory warning for the process id ${pids[0]}, bundle id ${bundleId}`);
47
- await device.devicectl.sendMemoryWarning(pids[0]);
26
+ // This regexp tries to match the process name of the main bundle executable.
27
+ // For example, if 'url' contains something like
28
+ // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/`
29
+ // and the following processes might be running:
30
+ // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/Target`
31
+ // `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/PlugIns/WidgetExtension.appex/WidgetExtension`
32
+ // then we only want to match the first one.
33
+ // Unfortunately devicectl does not provide more info which would
34
+ // allow to connect a bundle id to a process id.
35
+ const pattern = new RegExp(`^${_.escapeRegExp(appInfos[0].url)}[^/]+$`);
36
+ /** @type {number[]} */
37
+ const pids = (await device.devicectl.listProcesses())
38
+ .filter(({executable}) => pattern.test(executable))
39
+ .map(({processIdentifier}) => processIdentifier);
40
+ if (_.isEmpty(pids)) {
41
+ throw new errors.InvalidArgumentError(
42
+ `The application identified by ${bundleId} must be running in order to simulate the Low Memory warning`
43
+ );
48
44
  }
49
- };
45
+ this.log.info(`Emulating Low Memory warning for the process id ${pids[0]}, bundle id ${bundleId}`);
46
+ await device.devicectl.sendMemoryWarning(pids[0]);
47
+ }
50
48
 
51
49
  /**
52
50
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver