appium-android-driver 7.8.3 → 8.0.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 (261) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/lib/commands/app-management.d.ts +129 -5
  3. package/build/lib/commands/app-management.d.ts.map +1 -1
  4. package/build/lib/commands/app-management.js +433 -128
  5. package/build/lib/commands/app-management.js.map +1 -1
  6. package/build/lib/commands/appearance.d.ts +17 -4
  7. package/build/lib/commands/appearance.d.ts.map +1 -1
  8. package/build/lib/commands/appearance.js +32 -33
  9. package/build/lib/commands/appearance.js.map +1 -1
  10. package/build/lib/commands/context/cache.d.ts +19 -0
  11. package/build/lib/commands/context/cache.d.ts.map +1 -0
  12. package/build/lib/commands/context/cache.js +32 -0
  13. package/build/lib/commands/context/cache.js.map +1 -0
  14. package/build/lib/commands/context/exports.d.ts +141 -0
  15. package/build/lib/commands/context/exports.d.ts.map +1 -0
  16. package/build/lib/commands/context/exports.js +351 -0
  17. package/build/lib/commands/context/exports.js.map +1 -0
  18. package/build/lib/commands/context/helpers.d.ts +98 -0
  19. package/build/lib/commands/context/helpers.d.ts.map +1 -0
  20. package/build/lib/commands/context/helpers.js +715 -0
  21. package/build/lib/commands/context/helpers.js.map +1 -0
  22. package/build/lib/commands/device/common.d.ts +23 -0
  23. package/build/lib/commands/device/common.d.ts.map +1 -0
  24. package/build/lib/commands/device/common.js +230 -0
  25. package/build/lib/commands/device/common.js.map +1 -0
  26. package/build/lib/commands/device/emulator-actions.d.ts +114 -0
  27. package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
  28. package/build/lib/commands/device/emulator-actions.js +197 -0
  29. package/build/lib/commands/device/emulator-actions.js.map +1 -0
  30. package/build/lib/commands/device/emulator-console.d.ts +7 -0
  31. package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
  32. package/build/lib/commands/device/emulator-console.js +24 -0
  33. package/build/lib/commands/device/emulator-console.js.map +1 -0
  34. package/build/lib/commands/device/utils.d.ts +50 -0
  35. package/build/lib/commands/device/utils.d.ts.map +1 -0
  36. package/build/lib/commands/device/utils.js +238 -0
  37. package/build/lib/commands/device/utils.js.map +1 -0
  38. package/build/lib/commands/deviceidle.d.ts +8 -5
  39. package/build/lib/commands/deviceidle.d.ts.map +1 -1
  40. package/build/lib/commands/deviceidle.js +31 -37
  41. package/build/lib/commands/deviceidle.js.map +1 -1
  42. package/build/lib/commands/element.d.ts +99 -5
  43. package/build/lib/commands/element.d.ts.map +1 -1
  44. package/build/lib/commands/element.js +152 -116
  45. package/build/lib/commands/element.js.map +1 -1
  46. package/build/lib/commands/execute.d.ts +12 -4
  47. package/build/lib/commands/execute.d.ts.map +1 -1
  48. package/build/lib/commands/execute.js +83 -78
  49. package/build/lib/commands/execute.js.map +1 -1
  50. package/build/lib/commands/file-actions.d.ts +42 -5
  51. package/build/lib/commands/file-actions.d.ts.map +1 -1
  52. package/build/lib/commands/file-actions.js +230 -194
  53. package/build/lib/commands/file-actions.js.map +1 -1
  54. package/build/lib/commands/find.d.ts +5 -4
  55. package/build/lib/commands/find.d.ts.map +1 -1
  56. package/build/lib/commands/find.js +7 -10
  57. package/build/lib/commands/find.js.map +1 -1
  58. package/build/lib/commands/geolocation.d.ts +45 -0
  59. package/build/lib/commands/geolocation.d.ts.map +1 -0
  60. package/build/lib/commands/geolocation.js +182 -0
  61. package/build/lib/commands/geolocation.js.map +1 -0
  62. package/build/lib/commands/ime.d.ts +25 -5
  63. package/build/lib/commands/ime.d.ts.map +1 -1
  64. package/build/lib/commands/ime.js +59 -42
  65. package/build/lib/commands/ime.js.map +1 -1
  66. package/build/lib/commands/intent.d.ts +56 -5
  67. package/build/lib/commands/intent.d.ts.map +1 -1
  68. package/build/lib/commands/intent.js +135 -83
  69. package/build/lib/commands/intent.js.map +1 -1
  70. package/build/lib/commands/keyboard.d.ts +58 -4
  71. package/build/lib/commands/keyboard.d.ts.map +1 -1
  72. package/build/lib/commands/keyboard.js +119 -17
  73. package/build/lib/commands/keyboard.js.map +1 -1
  74. package/build/lib/commands/lock/exports.d.ts +301 -0
  75. package/build/lib/commands/lock/exports.d.ts.map +1 -0
  76. package/build/lib/commands/lock/exports.js +121 -0
  77. package/build/lib/commands/lock/exports.js.map +1 -0
  78. package/build/lib/commands/lock/helpers.d.ts +349 -0
  79. package/build/lib/commands/lock/helpers.d.ts.map +1 -0
  80. package/build/lib/commands/lock/helpers.js +375 -0
  81. package/build/lib/commands/lock/helpers.js.map +1 -0
  82. package/build/lib/commands/log.d.ts +59 -5
  83. package/build/lib/commands/log.d.ts.map +1 -1
  84. package/build/lib/commands/log.js +150 -140
  85. package/build/lib/commands/log.js.map +1 -1
  86. package/build/lib/commands/media-projection.d.ts +16 -5
  87. package/build/lib/commands/media-projection.d.ts.map +1 -1
  88. package/build/lib/commands/media-projection.js +69 -58
  89. package/build/lib/commands/media-projection.js.map +1 -1
  90. package/build/lib/commands/memory.d.ts +9 -5
  91. package/build/lib/commands/memory.d.ts.map +1 -1
  92. package/build/lib/commands/memory.js +19 -24
  93. package/build/lib/commands/memory.js.map +1 -1
  94. package/build/lib/commands/misc.d.ts +42 -0
  95. package/build/lib/commands/misc.d.ts.map +1 -0
  96. package/build/lib/commands/misc.js +100 -0
  97. package/build/lib/commands/misc.js.map +1 -0
  98. package/build/lib/commands/network.d.ts +61 -5
  99. package/build/lib/commands/network.d.ts.map +1 -1
  100. package/build/lib/commands/network.js +196 -189
  101. package/build/lib/commands/network.js.map +1 -1
  102. package/build/lib/commands/performance.d.ts +67 -27
  103. package/build/lib/commands/performance.d.ts.map +1 -1
  104. package/build/lib/commands/performance.js +105 -80
  105. package/build/lib/commands/performance.js.map +1 -1
  106. package/build/lib/commands/permissions.d.ts +12 -6
  107. package/build/lib/commands/permissions.d.ts.map +1 -1
  108. package/build/lib/commands/permissions.js +65 -62
  109. package/build/lib/commands/permissions.js.map +1 -1
  110. package/build/lib/commands/recordscreen.d.ts +44 -5
  111. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  112. package/build/lib/commands/recordscreen.js +131 -126
  113. package/build/lib/commands/recordscreen.js.map +1 -1
  114. package/build/lib/commands/resources.d.ts +16 -0
  115. package/build/lib/commands/resources.d.ts.map +1 -0
  116. package/build/lib/commands/resources.js +91 -0
  117. package/build/lib/commands/resources.js.map +1 -0
  118. package/build/lib/commands/shell.d.ts +8 -5
  119. package/build/lib/commands/shell.d.ts.map +1 -1
  120. package/build/lib/commands/shell.js +29 -33
  121. package/build/lib/commands/shell.js.map +1 -1
  122. package/build/lib/commands/streamscreen.d.ts +34 -6
  123. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  124. package/build/lib/commands/streamscreen.js +166 -162
  125. package/build/lib/commands/streamscreen.js.map +1 -1
  126. package/build/lib/commands/system-bars.d.ts +18 -13
  127. package/build/lib/commands/system-bars.d.ts.map +1 -1
  128. package/build/lib/commands/system-bars.js +68 -64
  129. package/build/lib/commands/system-bars.js.map +1 -1
  130. package/build/lib/commands/time.d.ts +14 -0
  131. package/build/lib/commands/time.d.ts.map +1 -0
  132. package/build/lib/commands/time.js +39 -0
  133. package/build/lib/commands/time.js.map +1 -0
  134. package/build/lib/commands/touch.d.ts +99 -6
  135. package/build/lib/commands/touch.d.ts.map +1 -1
  136. package/build/lib/commands/touch.js +399 -280
  137. package/build/lib/commands/touch.js.map +1 -1
  138. package/build/lib/commands/types.d.ts +110 -2
  139. package/build/lib/commands/types.d.ts.map +1 -1
  140. package/build/lib/doctor/checks.d.ts.map +1 -1
  141. package/build/lib/doctor/checks.js +4 -4
  142. package/build/lib/doctor/checks.js.map +1 -1
  143. package/build/lib/driver.d.ts +224 -27
  144. package/build/lib/driver.d.ts.map +1 -1
  145. package/build/lib/driver.js +232 -7
  146. package/build/lib/driver.js.map +1 -1
  147. package/build/lib/index.d.ts +1 -4
  148. package/build/lib/index.d.ts.map +1 -1
  149. package/build/lib/index.js +1 -13
  150. package/build/lib/index.js.map +1 -1
  151. package/build/lib/logger.js.map +1 -1
  152. package/build/lib/method-map.d.ts +0 -23
  153. package/build/lib/method-map.d.ts.map +1 -1
  154. package/build/lib/method-map.js +0 -11
  155. package/build/lib/method-map.js.map +1 -1
  156. package/build/lib/utils.d.ts +12 -0
  157. package/build/lib/utils.d.ts.map +1 -1
  158. package/build/lib/utils.js +38 -2
  159. package/build/lib/utils.js.map +1 -1
  160. package/lib/commands/app-management.js +470 -145
  161. package/lib/commands/appearance.js +29 -36
  162. package/lib/commands/context/cache.js +29 -0
  163. package/lib/commands/context/exports.js +379 -0
  164. package/lib/commands/context/helpers.js +802 -0
  165. package/lib/commands/device/common.js +264 -0
  166. package/lib/commands/device/emulator-actions.js +194 -0
  167. package/lib/commands/device/emulator-console.js +24 -0
  168. package/lib/commands/device/utils.js +285 -0
  169. package/lib/commands/deviceidle.js +31 -44
  170. package/lib/commands/element.js +149 -142
  171. package/lib/commands/execute.js +86 -87
  172. package/lib/commands/file-actions.js +249 -222
  173. package/lib/commands/find.ts +13 -19
  174. package/lib/commands/geolocation.js +179 -0
  175. package/lib/commands/ime.js +53 -45
  176. package/lib/commands/intent.js +149 -91
  177. package/lib/commands/keyboard.js +114 -17
  178. package/lib/commands/lock/exports.js +139 -0
  179. package/lib/commands/lock/helpers.js +379 -0
  180. package/lib/commands/log.js +170 -166
  181. package/lib/commands/media-projection.js +75 -70
  182. package/lib/commands/memory.js +17 -29
  183. package/lib/commands/misc.js +94 -0
  184. package/lib/commands/network.js +209 -223
  185. package/lib/commands/performance.js +88 -73
  186. package/lib/commands/permissions.js +83 -84
  187. package/lib/commands/recordscreen.js +171 -170
  188. package/lib/commands/resources.js +96 -0
  189. package/lib/commands/shell.js +28 -42
  190. package/lib/commands/streamscreen.js +207 -206
  191. package/lib/commands/system-bars.js +76 -77
  192. package/lib/commands/time.js +36 -0
  193. package/lib/commands/touch.js +442 -346
  194. package/lib/commands/types.ts +123 -2
  195. package/lib/doctor/checks.js +24 -16
  196. package/lib/driver.ts +454 -12
  197. package/lib/index.ts +1 -13
  198. package/lib/logger.js +1 -1
  199. package/lib/method-map.js +0 -11
  200. package/lib/utils.js +40 -3
  201. package/package.json +1 -1
  202. package/build/lib/commands/actions.d.ts +0 -8
  203. package/build/lib/commands/actions.d.ts.map +0 -1
  204. package/build/lib/commands/actions.js +0 -207
  205. package/build/lib/commands/actions.js.map +0 -1
  206. package/build/lib/commands/alert.d.ts +0 -8
  207. package/build/lib/commands/alert.d.ts.map +0 -1
  208. package/build/lib/commands/alert.js +0 -29
  209. package/build/lib/commands/alert.js.map +0 -1
  210. package/build/lib/commands/context.d.ts +0 -10
  211. package/build/lib/commands/context.d.ts.map +0 -1
  212. package/build/lib/commands/context.js +0 -431
  213. package/build/lib/commands/context.js.map +0 -1
  214. package/build/lib/commands/emu-console.d.ts +0 -7
  215. package/build/lib/commands/emu-console.d.ts.map +0 -1
  216. package/build/lib/commands/emu-console.js +0 -27
  217. package/build/lib/commands/emu-console.js.map +0 -1
  218. package/build/lib/commands/general.d.ts +0 -9
  219. package/build/lib/commands/general.d.ts.map +0 -1
  220. package/build/lib/commands/general.js +0 -293
  221. package/build/lib/commands/general.js.map +0 -1
  222. package/build/lib/commands/index.d.ts +0 -28
  223. package/build/lib/commands/index.d.ts.map +0 -1
  224. package/build/lib/commands/index.js +0 -57
  225. package/build/lib/commands/index.js.map +0 -1
  226. package/build/lib/commands/mixins.d.ts +0 -747
  227. package/build/lib/commands/mixins.d.ts.map +0 -1
  228. package/build/lib/commands/mixins.js +0 -19
  229. package/build/lib/commands/mixins.js.map +0 -1
  230. package/build/lib/helpers/android.d.ts +0 -163
  231. package/build/lib/helpers/android.d.ts.map +0 -1
  232. package/build/lib/helpers/android.js +0 -818
  233. package/build/lib/helpers/android.js.map +0 -1
  234. package/build/lib/helpers/index.d.ts +0 -7
  235. package/build/lib/helpers/index.d.ts.map +0 -1
  236. package/build/lib/helpers/index.js +0 -29
  237. package/build/lib/helpers/index.js.map +0 -1
  238. package/build/lib/helpers/types.d.ts +0 -122
  239. package/build/lib/helpers/types.d.ts.map +0 -1
  240. package/build/lib/helpers/types.js +0 -3
  241. package/build/lib/helpers/types.js.map +0 -1
  242. package/build/lib/helpers/unlock.d.ts +0 -32
  243. package/build/lib/helpers/unlock.d.ts.map +0 -1
  244. package/build/lib/helpers/unlock.js +0 -273
  245. package/build/lib/helpers/unlock.js.map +0 -1
  246. package/build/lib/helpers/webview.d.ts +0 -74
  247. package/build/lib/helpers/webview.d.ts.map +0 -1
  248. package/build/lib/helpers/webview.js +0 -448
  249. package/build/lib/helpers/webview.js.map +0 -1
  250. package/lib/commands/actions.js +0 -244
  251. package/lib/commands/alert.js +0 -34
  252. package/lib/commands/context.js +0 -507
  253. package/lib/commands/emu-console.js +0 -31
  254. package/lib/commands/general.js +0 -343
  255. package/lib/commands/index.ts +0 -54
  256. package/lib/commands/mixins.ts +0 -976
  257. package/lib/helpers/android.ts +0 -1153
  258. package/lib/helpers/index.ts +0 -6
  259. package/lib/helpers/types.ts +0 -136
  260. package/lib/helpers/unlock.ts +0 -329
  261. package/lib/helpers/webview.ts +0 -610
@@ -1,610 +0,0 @@
1
- /**
2
- * Webview-related helper functions
3
- * @module
4
- */
5
-
6
- import {util, timing} from '@appium/support';
7
- import {StringRecord} from '@appium/types';
8
- import axios from 'axios';
9
- import B from 'bluebird';
10
- import _ from 'lodash';
11
- import {LRUCache} from 'lru-cache';
12
- import os from 'node:os';
13
- import path from 'node:path';
14
- import http from 'node:http';
15
- import {findAPortNotInUse} from 'portscanner';
16
- import type {WebviewsMapping} from '../commands/types';
17
- import type {AndroidDriverCaps} from '../driver';
18
- import logger from '../logger';
19
- import type {
20
- DetailCollectionOptions,
21
- GetWebviewsOpts,
22
- WebViewDetails,
23
- WebviewProc,
24
- WebviewProps,
25
- } from './types';
26
- import type {ADB} from 'appium-adb';
27
- import {sleep} from 'asyncbox';
28
-
29
- const NATIVE_WIN = 'NATIVE_APP';
30
- const WEBVIEW_WIN = 'WEBVIEW';
31
- const CHROMIUM_WIN = 'CHROMIUM';
32
- const WEBVIEW_BASE = `${WEBVIEW_WIN}_`;
33
- const WEBVIEW_PID_PATTERN = new RegExp(`^${WEBVIEW_BASE}(\\d+)`);
34
- const WEBVIEW_PKG_PATTERN = new RegExp(`^${WEBVIEW_BASE}([^\\d\\s][\\w.]*)`);
35
- export const DEVTOOLS_SOCKET_PATTERN = /@[\w.]+_devtools_remote_?([\w.]+_)?(\d+)?\b/;
36
- const CROSSWALK_SOCKET_PATTERN = /@([\w.]+)_devtools_remote\b/;
37
- const CHROMIUM_DEVTOOLS_SOCKET = 'chrome_devtools_remote';
38
- const CHROME_PACKAGE_NAME = 'com.android.chrome';
39
- const KNOWN_CHROME_PACKAGE_NAMES = [
40
- CHROME_PACKAGE_NAME,
41
- 'com.chrome.beta',
42
- 'com.chrome.dev',
43
- 'com.chrome.canary',
44
- ];
45
- const DEVTOOLS_PORTS_RANGE = [10900, 11000];
46
- const WEBVIEWS_DETAILS_CACHE = new LRUCache<string, WebViewDetails>({
47
- max: 100,
48
- updateAgeOnGet: true,
49
- });
50
- const CDP_REQ_TIMEOUT = 2000; // ms
51
- const DEVTOOLS_PORT_ALLOCATION_GUARD = util.getLockFileGuard(
52
- path.resolve(os.tmpdir(), 'android_devtools_port_guard'),
53
- {timeout: 7, tryRecovery: true},
54
- );
55
- const WEBVIEW_WAIT_INTERVAL_MS = 200;
56
-
57
- interface WebviewHelpers {
58
- /**
59
- * Take a webview name like WEBVIEW_4296 and use 'adb shell ps' to figure out
60
- * which app package is associated with that webview. One of the reasons we
61
- * want to do this is to make sure we're listing webviews for the actual AUT,
62
- * not some other running app
63
- *
64
- * @param adb - an ADB instance
65
- * @param webview - a webview process name
66
- *
67
- * @returns {Promise<string>} - the package name of the app running the webview
68
- * @throws {Error} If there was a failure while retrieving the process name
69
- */
70
- procFromWebview: (adb: ADB, webview: string) => Promise<string>;
71
-
72
- /**
73
- * Parse webview names for getContexts
74
- *
75
- * @param webviewsMapping See note on getWebViewsMapping
76
- * @param opts See note on getWebViewsMapping
77
- * @returns a list of webview names
78
- */
79
- parseWebviewNames: (webviewsMapping: WebviewsMapping[], opts?: GetWebviewsOpts) => string[];
80
-
81
- /**
82
- * Get a list of available webviews mapping by introspecting processes with adb,
83
- * where webviews are listed. It's possible to pass in a 'deviceSocket' arg, which
84
- * limits the webview possibilities to the one running on the Chromium devtools
85
- * socket we're interested in (see note on webviewsFromProcs). We can also
86
- * direct this method to verify whether a particular webview process actually
87
- * has any pages (if a process exists but no pages are found, Chromedriver will
88
- * not actually be able to connect to it, so this serves as a guard for that
89
- * strange failure mode). The strategy for checking whether any pages are
90
- * active involves sending a request to the remote debug server on the device,
91
- * hence it is also possible to specify the port on the host machine which
92
- * should be used for this communication.
93
- *
94
- * @param adb - an ADB instance
95
- */
96
- getWebViewsMapping: (adb: ADB, opts?: GetWebviewsOpts) => Promise<WebviewsMapping[]>;
97
-
98
- /**
99
- * Retrieves web view details previously cached by `getWebviews` call
100
- *
101
- * @param adb ADB instance
102
- * @param webview The name of the web view
103
- * @returns Either `undefined` or the recent web view details
104
- */
105
- getWebviewDetails: (adb: ADB, webview: string) => WebViewDetails | undefined;
106
-
107
- /**
108
- * Create Chrome driver capabilities based on the provided
109
- * Appium capabilities
110
- *
111
- * @param opts User-provided capabilities object
112
- * @param deviceId The identifier of the Android device under test
113
- * @returns The capabilities object.
114
- * @see {@link https://chromedriver.chromium.org/capabilities Chromedriver docs} for more details
115
- */
116
-
117
- createChromedriverCaps: (
118
- opts: any,
119
- deviceId: string,
120
- webViewDetails?: WebViewDetails | null,
121
- ) => object;
122
- }
123
-
124
- function toDetailsCacheKey(adb: ADB, webview: string): string {
125
- return `${adb?.curDeviceId}:${webview}`;
126
- }
127
-
128
- /**
129
- * This function gets a list of android system processes and returns ones
130
- * that look like webviews
131
- * See https://cs.chromium.org/chromium/src/chrome/browser/devtools/device/android_device_info_query.cc
132
- * for more details
133
- *
134
- * @param adb - an ADB instance
135
- *
136
- * @returns a list of matching webview socket names (including the leading '@')
137
- */
138
- async function getPotentialWebviewProcs(adb: ADB): Promise<string[]> {
139
- const out = (await adb.shell(['cat', '/proc/net/unix'])) as string;
140
- const names: string[] = [];
141
- const allMatches: string[] = [];
142
- for (const line of out.split('\n')) {
143
- // Num RefCount Protocol Flags Type St Inode Path
144
- const [, , , flags, , st, , sockPath] = line.trim().split(/\s+/);
145
- if (!sockPath) {
146
- continue;
147
- }
148
- if (sockPath.startsWith('@')) {
149
- allMatches.push(line.trim());
150
- }
151
- if (flags !== '00010000' || st !== '01') {
152
- continue;
153
- }
154
- if (!DEVTOOLS_SOCKET_PATTERN.test(sockPath)) {
155
- continue;
156
- }
157
-
158
- names.push(sockPath);
159
- }
160
- if (_.isEmpty(names)) {
161
- logger.debug('Found no active devtools sockets');
162
- if (!_.isEmpty(allMatches)) {
163
- logger.debug(`Other sockets are: ${JSON.stringify(allMatches, null, 2)}`);
164
- }
165
- } else {
166
- logger.debug(
167
- `Parsed ${names.length} active devtools ${util.pluralize('socket', names.length, false)}: ` +
168
- JSON.stringify(names),
169
- );
170
- }
171
- // sometimes the webview process shows up multiple times per app
172
- return _.uniq(names);
173
- }
174
-
175
- /**
176
- * This function retrieves a list of system processes that look like webviews,
177
- * and returns them along with the webview context name appropriate for it.
178
- * If we pass in a deviceSocket, we only attempt to find webviews which match
179
- * that socket name (this is for apps which embed Chromium, which isn't the
180
- * same as chrome-backed webviews).
181
- *
182
- * @param adb - an ADB instance
183
- * @param deviceSocket - the explictly-named device socket to use
184
- */
185
- async function webviewsFromProcs(
186
- adb: any,
187
- deviceSocket: string | null = null,
188
- ): Promise<WebviewProc[]> {
189
- const socketNames = await getPotentialWebviewProcs(adb);
190
- const webviews: {proc: string; webview: string}[] = [];
191
- for (const socketName of socketNames) {
192
- if (deviceSocket === CHROMIUM_DEVTOOLS_SOCKET && socketName === `@${deviceSocket}`) {
193
- webviews.push({
194
- proc: socketName,
195
- webview: CHROMIUM_WIN,
196
- });
197
- continue;
198
- }
199
-
200
- const socketNameMatch = DEVTOOLS_SOCKET_PATTERN.exec(socketName);
201
- if (!socketNameMatch) {
202
- continue;
203
- }
204
- const matchedSocketName = socketNameMatch[2];
205
- const crosswalkMatch = CROSSWALK_SOCKET_PATTERN.exec(socketName);
206
- if (!matchedSocketName && !crosswalkMatch) {
207
- continue;
208
- }
209
-
210
- if ((deviceSocket && socketName === `@${deviceSocket}`) || !deviceSocket) {
211
- webviews.push({
212
- proc: socketName,
213
- webview: matchedSocketName
214
- ? `${WEBVIEW_BASE}${matchedSocketName}`
215
- : // @ts-expect-error: XXX crosswalkMatch can absolutely be null
216
- `${WEBVIEW_BASE}${crosswalkMatch[1]}`,
217
- });
218
- }
219
- }
220
- return webviews;
221
- }
222
-
223
- /**
224
- * Allocates a local port for devtools communication
225
- *
226
- * @param adb - ADB instance
227
- * @param socketName - The remote Unix socket name
228
- * @param webviewDevtoolsPort - The local port number or null to apply
229
- * autodetection
230
- * @returns The host name and the port number to connect to if the
231
- * remote socket has been forwarded successfully
232
- * @throws {Error} If there was an error while allocating the local port
233
- */
234
- async function allocateDevtoolsChannel(
235
- adb: any,
236
- socketName: string,
237
- webviewDevtoolsPort: number | null = null,
238
- ): Promise<[string, number]> {
239
- // socket names come with '@', but this should not be a part of the abstract
240
- // remote port, so remove it
241
- const remotePort = socketName.replace(/^@/, '');
242
- let [startPort, endPort] = DEVTOOLS_PORTS_RANGE;
243
- if (webviewDevtoolsPort) {
244
- endPort = webviewDevtoolsPort + (endPort - startPort);
245
- startPort = webviewDevtoolsPort;
246
- }
247
- logger.debug(
248
- `Forwarding remote port ${remotePort} to a local ` + `port in range ${startPort}..${endPort}`,
249
- );
250
- if (!webviewDevtoolsPort) {
251
- logger.debug(
252
- `You could use the 'webviewDevtoolsPort' capability to customize ` +
253
- `the starting port number`,
254
- );
255
- }
256
- const port = (await DEVTOOLS_PORT_ALLOCATION_GUARD(async () => {
257
- let localPort: number;
258
- try {
259
- localPort = await findAPortNotInUse(startPort, endPort);
260
- } catch (e) {
261
- throw new Error(
262
- `Cannot find any free port to forward the Devtools socket ` +
263
- `in range ${startPort}..${endPort}. You could set the starting port number ` +
264
- `manually by providing the 'webviewDevtoolsPort' capability`,
265
- );
266
- }
267
- await adb.adbExec(['forward', `tcp:${localPort}`, `localabstract:${remotePort}`]);
268
- return localPort;
269
- })) as number;
270
- return [adb.adbHost ?? '127.0.0.1', port];
271
- }
272
-
273
- /**
274
- * This is a wrapper for Chrome Debugger Protocol data collection.
275
- * No error is thrown if CDP request fails - in such case no data will be
276
- * recorded into the corresponding `webviewsMapping` item.
277
- *
278
- * @param adb The ADB instance
279
- * @param webviewsMapping The current webviews mapping
280
- * !!! Each item of this array gets mutated (`info`/`pages` properties get added
281
- * based on the provided `opts`) if the requested details have been
282
- * successfully retrieved for it !!!
283
- * @param opts If both `ensureWebviewsHavePages` and
284
- * `enableWebviewDetailsCollection` properties are falsy then no details collection
285
- * is performed
286
- */
287
- async function collectWebviewsDetails(
288
- adb: ADB,
289
- webviewsMapping: WebviewProps[],
290
- opts: DetailCollectionOptions = {},
291
- ): Promise<void> {
292
- if (_.isEmpty(webviewsMapping)) {
293
- return;
294
- }
295
-
296
- const {
297
- webviewDevtoolsPort = null,
298
- ensureWebviewsHavePages = null,
299
- enableWebviewDetailsCollection = null,
300
- } = opts;
301
-
302
- if (!ensureWebviewsHavePages) {
303
- logger.info(
304
- `Not checking whether webviews have active pages; use the ` +
305
- `'ensureWebviewsHavePages' cap to turn this check on`,
306
- );
307
- }
308
-
309
- if (!enableWebviewDetailsCollection) {
310
- logger.info(
311
- `Not collecting web view details. Details collection might help ` +
312
- `to make Chromedriver initialization more precise. Use the 'enableWebviewDetailsCollection' ` +
313
- `cap to turn it on`,
314
- );
315
- }
316
-
317
- if (!ensureWebviewsHavePages && !enableWebviewDetailsCollection) {
318
- return;
319
- }
320
-
321
- // Connect to each devtools socket and retrieve web view details
322
- logger.debug(`Collecting CDP data of ${util.pluralize('webview', webviewsMapping.length, true)}`);
323
- const detailCollectors: Promise<void>[] = [];
324
- for (const item of webviewsMapping) {
325
- detailCollectors.push(
326
- (async () => {
327
- let port: number | undefined;
328
- let host: string | undefined;
329
- try {
330
- [host, port] = await allocateDevtoolsChannel(adb, item.proc, webviewDevtoolsPort);
331
- if (enableWebviewDetailsCollection) {
332
- item.info = await cdpInfo(host, port);
333
- }
334
- if (ensureWebviewsHavePages) {
335
- item.pages = await cdpList(host, port);
336
- }
337
- } catch (e) {
338
- logger.debug(e);
339
- } finally {
340
- if (port) {
341
- try {
342
- await adb.removePortForward(port);
343
- } catch (e) {
344
- logger.debug(e);
345
- }
346
- }
347
- }
348
- })(),
349
- );
350
- }
351
- await B.all(detailCollectors);
352
- logger.debug(`CDP data collection completed`);
353
- }
354
-
355
- // https://chromedevtools.github.io/devtools-protocol/
356
- async function cdpGetRequest(host: string, port: number, endpoint: string): Promise<object[]> {
357
- return (
358
- await axios({
359
- url: `http://${host}:${port}${endpoint}`,
360
- timeout: CDP_REQ_TIMEOUT,
361
- // We need to set this from Node.js v19 onwards.
362
- // Otherwise, in situation with multiple webviews,
363
- // the preceding webview pages will be incorrectly retrieved as the current ones.
364
- // https://nodejs.org/en/blog/announcements/v19-release-announce#https11-keepalive-by-default
365
- httpAgent: new http.Agent({keepAlive: false}),
366
- })
367
- ).data;
368
- }
369
-
370
- async function cdpList(host: string, port: number): Promise<object[]> {
371
- return cdpGetRequest(host, port, '/json/list');
372
- }
373
-
374
- async function cdpInfo(host: string, port: number): Promise<object[]> {
375
- return cdpGetRequest(host, port, '/json/version');
376
- }
377
-
378
- const WebviewHelpers: WebviewHelpers = {
379
- async procFromWebview(adb: ADB, webview: string): Promise<string> {
380
- const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
381
- if (!pidMatch) {
382
- throw new Error(`Could not find PID for webview '${webview}'`);
383
- }
384
-
385
- const pid = pidMatch[1];
386
- logger.debug(`${webview} mapped to pid ${pid}`);
387
- logger.debug(`Getting process name for webview '${webview}'`);
388
- const pkg = await adb.getNameByPid(pid);
389
- logger.debug(`Got process name: '${pkg}'`);
390
- return pkg;
391
- },
392
-
393
- parseWebviewNames(
394
- webviewsMapping: WebviewsMapping[],
395
- {ensureWebviewsHavePages = true, isChromeSession = false}: GetWebviewsOpts = {},
396
- ): string[] {
397
- if (isChromeSession) {
398
- return [CHROMIUM_WIN];
399
- }
400
-
401
- const result: string[] = [];
402
- for (const {webview, pages, proc, webviewName} of webviewsMapping) {
403
- if (ensureWebviewsHavePages) {
404
- if (_.isUndefined(pages)) {
405
- logger.info(`Skipping the webview '${webview}' at '${proc}' since it is unreachable`);
406
- continue;
407
- }
408
- if (!pages?.length) {
409
- logger.info(
410
- `Skipping the webview '${webview}' at '${proc}' ` +
411
- `since it has reported having zero pages`,
412
- );
413
- continue;
414
- }
415
- }
416
- if (webviewName) {
417
- result.push(webviewName);
418
- }
419
- }
420
- logger.debug(
421
- `Found ${util.pluralize('webview', result.length, true)}: ${JSON.stringify(result)}`,
422
- );
423
- return result;
424
- },
425
-
426
- async getWebViewsMapping(
427
- adb: ADB,
428
- {
429
- androidDeviceSocket = null,
430
- ensureWebviewsHavePages = true,
431
- webviewDevtoolsPort = null,
432
- enableWebviewDetailsCollection = true,
433
- waitForWebviewMs = 0,
434
- }: GetWebviewsOpts = {},
435
- ): Promise<WebviewsMapping[]> {
436
- logger.debug(`Getting a list of available webviews`);
437
-
438
- if (!_.isNumber(waitForWebviewMs)) {
439
- waitForWebviewMs = parseInt(waitForWebviewMs, 10) || 0;
440
- }
441
-
442
- let webviewsMapping: WebviewsMapping[];
443
- const timer = new timing.Timer().start();
444
- do {
445
- webviewsMapping = (await webviewsFromProcs(adb, androidDeviceSocket)) as WebviewsMapping[];
446
-
447
- if (webviewsMapping.length > 0) {
448
- break;
449
- }
450
-
451
- logger.debug(`No webviews found in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
452
- await sleep(WEBVIEW_WAIT_INTERVAL_MS);
453
- } while (timer.getDuration().asMilliSeconds < waitForWebviewMs);
454
-
455
- await collectWebviewsDetails(adb, webviewsMapping, {
456
- ensureWebviewsHavePages,
457
- enableWebviewDetailsCollection,
458
- webviewDevtoolsPort,
459
- });
460
-
461
- for (const webviewMapping of webviewsMapping) {
462
- const {webview, info} = webviewMapping;
463
- webviewMapping.webviewName = null;
464
-
465
- let wvName = webview;
466
- let process: {name: string; id: string | null} | undefined;
467
- if (!androidDeviceSocket) {
468
- const pkgMatch = WEBVIEW_PKG_PATTERN.exec(webview);
469
- try {
470
- // web view name could either be suffixed with PID or the package name
471
- // package names could not start with a digit
472
- const pkg = pkgMatch ? pkgMatch[1] : await WebviewHelpers.procFromWebview(adb, webview);
473
- wvName = `${WEBVIEW_BASE}${pkg}`;
474
- const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
475
- process = {
476
- name: pkg,
477
- id: pidMatch ? pidMatch[1] : null,
478
- };
479
- } catch (e) {
480
- logger.warn((e as Error).message);
481
- continue;
482
- }
483
- }
484
-
485
- webviewMapping.webviewName = wvName;
486
- const key = toDetailsCacheKey(adb, wvName);
487
- if (info || process) {
488
- WEBVIEWS_DETAILS_CACHE.set(key, {info, process});
489
- } else if (WEBVIEWS_DETAILS_CACHE.has(key)) {
490
- WEBVIEWS_DETAILS_CACHE.delete(key);
491
- }
492
- }
493
- return webviewsMapping;
494
- },
495
-
496
- getWebviewDetails(adb: ADB, webview: string): WebViewDetails | undefined {
497
- const key = toDetailsCacheKey(adb, webview);
498
- return WEBVIEWS_DETAILS_CACHE.get(key);
499
- },
500
-
501
- createChromedriverCaps(
502
- opts: any,
503
- deviceId: string,
504
- webViewDetails?: WebViewDetails | null,
505
- ): object {
506
- const caps: AndroidDriverCaps & {chromeOptions: StringRecord} = {chromeOptions: {}} as any;
507
-
508
- const androidPackage =
509
- opts.chromeOptions?.androidPackage ||
510
- opts.appPackage ||
511
- webViewDetails?.info?.['Android-Package'];
512
- if (androidPackage) {
513
- // chromedriver raises an invalid argument error when androidPackage is 'null'
514
-
515
- caps.chromeOptions.androidPackage = androidPackage;
516
- }
517
- if (_.isBoolean(opts.chromeUseRunningApp)) {
518
- caps.chromeOptions.androidUseRunningApp = opts.chromeUseRunningApp;
519
- }
520
- if (opts.chromeAndroidPackage) {
521
- caps.chromeOptions.androidPackage = opts.chromeAndroidPackage;
522
- }
523
- if (opts.chromeAndroidActivity) {
524
- caps.chromeOptions.androidActivity = opts.chromeAndroidActivity;
525
- }
526
- if (opts.chromeAndroidProcess) {
527
- caps.chromeOptions.androidProcess = opts.chromeAndroidProcess;
528
- } else if (webViewDetails?.process?.name && webViewDetails?.process?.id) {
529
- caps.chromeOptions.androidProcess = webViewDetails.process.name;
530
- }
531
- if (_.toLower(opts.browserName) === 'chromium-webview') {
532
- caps.chromeOptions.androidActivity = opts.appActivity;
533
- }
534
- if (opts.pageLoadStrategy) {
535
- caps.pageLoadStrategy = opts.pageLoadStrategy;
536
- }
537
- const isChrome = _.toLower(caps.chromeOptions.androidPackage) === 'chrome';
538
- if (_.includes(KNOWN_CHROME_PACKAGE_NAMES, caps.chromeOptions.androidPackage) || isChrome) {
539
- // if we have extracted package from context name, it could come in as bare
540
- // "chrome", and so we should make sure the details are correct, including
541
- // not using an activity or process id
542
- if (isChrome) {
543
- caps.chromeOptions.androidPackage = CHROME_PACKAGE_NAME;
544
- }
545
- delete caps.chromeOptions.androidActivity;
546
- delete caps.chromeOptions.androidProcess;
547
- }
548
- // add device id from adb
549
- caps.chromeOptions.androidDeviceSerial = deviceId;
550
-
551
- if (_.isPlainObject(opts.loggingPrefs) || _.isPlainObject(opts.chromeLoggingPrefs)) {
552
- if (opts.loggingPrefs) {
553
- logger.warn(
554
- `The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`,
555
- );
556
- }
557
- // @ts-expect-error Why are we using this if it's deprecated?
558
- caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
559
- }
560
- if (opts.enablePerformanceLogging) {
561
- logger.warn(
562
- `The 'enablePerformanceLogging' cap is deprecated; simply use ` +
563
- `the 'chromeLoggingPrefs' cap instead, with a 'performance' key set to 'ALL'`,
564
- );
565
- const newPref = {performance: 'ALL'};
566
- // don't overwrite other logging prefs that have been sent in if they exist
567
- // @ts-expect-error Why are we using this if it's deprecated?
568
- caps.loggingPrefs = caps.loggingPrefs
569
- ? // @ts-expect-error Why are we using this if it's deprecated?
570
- Object.assign({}, caps.loggingPrefs, newPref)
571
- : newPref;
572
- }
573
-
574
- if (opts.chromeOptions?.Arguments) {
575
- // merge `Arguments` and `args`
576
- opts.chromeOptions.args = [
577
- ...(opts.chromeOptions.args || []),
578
- ...opts.chromeOptions.Arguments,
579
- ];
580
- delete opts.chromeOptions.Arguments;
581
- }
582
-
583
- logger.debug(
584
- 'Precalculated Chromedriver capabilities: ' + JSON.stringify(caps.chromeOptions, null, 2),
585
- );
586
-
587
- const protectedCapNames: string[] = [];
588
- for (const [opt, val] of _.toPairs(opts.chromeOptions)) {
589
- if (_.isUndefined(caps.chromeOptions[opt])) {
590
- caps.chromeOptions[opt] = val;
591
- } else {
592
- protectedCapNames.push(opt);
593
- }
594
- }
595
- if (!_.isEmpty(protectedCapNames)) {
596
- logger.info(
597
- 'The following Chromedriver capabilities cannot be overridden ' +
598
- 'by the provided chromeOptions:',
599
- );
600
- for (const optName of protectedCapNames) {
601
- logger.info(` ${optName} (${JSON.stringify(opts.chromeOptions[optName])})`);
602
- }
603
- }
604
-
605
- return caps;
606
- },
607
- };
608
-
609
- export {CHROMIUM_WIN, KNOWN_CHROME_PACKAGE_NAMES, NATIVE_WIN, WEBVIEW_BASE, WEBVIEW_WIN};
610
- export default WebviewHelpers;