appium-remote-debugger 15.7.3 → 15.8.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 (70) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/lib/atoms.d.ts.map +1 -1
  3. package/build/lib/atoms.js +27 -28
  4. package/build/lib/atoms.js.map +1 -1
  5. package/build/lib/index.d.ts.map +1 -1
  6. package/build/lib/index.js +7 -0
  7. package/build/lib/index.js.map +1 -1
  8. package/build/lib/mixins/connect.d.ts.map +1 -1
  9. package/build/lib/mixins/connect.js +21 -25
  10. package/build/lib/mixins/connect.js.map +1 -1
  11. package/build/lib/mixins/execute.d.ts.map +1 -1
  12. package/build/lib/mixins/execute.js +2 -8
  13. package/build/lib/mixins/execute.js.map +1 -1
  14. package/build/lib/mixins/message-handlers.d.ts.map +1 -1
  15. package/build/lib/mixins/message-handlers.js +8 -12
  16. package/build/lib/mixins/message-handlers.js.map +1 -1
  17. package/build/lib/mixins/misc.d.ts.map +1 -1
  18. package/build/lib/mixins/misc.js +5 -39
  19. package/build/lib/mixins/misc.js.map +1 -1
  20. package/build/lib/mixins/navigate.d.ts.map +1 -1
  21. package/build/lib/mixins/navigate.js +20 -55
  22. package/build/lib/mixins/navigate.js.map +1 -1
  23. package/build/lib/mixins/property-accessors.d.ts +24 -0
  24. package/build/lib/mixins/property-accessors.d.ts.map +1 -1
  25. package/build/lib/mixins/property-accessors.js +24 -0
  26. package/build/lib/mixins/property-accessors.js.map +1 -1
  27. package/build/lib/remote-debugger.d.ts +38 -38
  28. package/build/lib/remote-debugger.d.ts.map +1 -1
  29. package/build/lib/remote-debugger.js +64 -69
  30. package/build/lib/remote-debugger.js.map +1 -1
  31. package/build/lib/rpc/remote-messages.d.ts.map +1 -1
  32. package/build/lib/rpc/remote-messages.js +7 -8
  33. package/build/lib/rpc/remote-messages.js.map +1 -1
  34. package/build/lib/rpc/rpc-client-real-device-shim.d.ts.map +1 -1
  35. package/build/lib/rpc/rpc-client-real-device-shim.js +3 -6
  36. package/build/lib/rpc/rpc-client-real-device-shim.js.map +1 -1
  37. package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -1
  38. package/build/lib/rpc/rpc-client-simulator.js +3 -5
  39. package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
  40. package/build/lib/rpc/rpc-client.d.ts +27 -27
  41. package/build/lib/rpc/rpc-client.d.ts.map +1 -1
  42. package/build/lib/rpc/rpc-client.js +226 -224
  43. package/build/lib/rpc/rpc-client.js.map +1 -1
  44. package/build/lib/rpc/rpc-message-handler.js +7 -10
  45. package/build/lib/rpc/rpc-message-handler.js.map +1 -1
  46. package/build/lib/types.d.ts +19 -19
  47. package/build/lib/types.d.ts.map +1 -1
  48. package/build/lib/utils.d.ts +70 -4
  49. package/build/lib/utils.d.ts.map +1 -1
  50. package/build/lib/utils.js +171 -23
  51. package/build/lib/utils.js.map +1 -1
  52. package/lib/atoms.ts +31 -32
  53. package/lib/index.ts +7 -0
  54. package/lib/mixins/connect.ts +22 -23
  55. package/lib/mixins/execute.ts +3 -5
  56. package/lib/mixins/message-handlers.ts +9 -10
  57. package/lib/mixins/misc.ts +8 -7
  58. package/lib/mixins/navigate.ts +58 -63
  59. package/lib/mixins/property-accessors.ts +24 -0
  60. package/lib/remote-debugger.ts +74 -76
  61. package/lib/rpc/remote-messages.ts +10 -5
  62. package/lib/rpc/rpc-client-real-device-shim.ts +3 -3
  63. package/lib/rpc/rpc-client-simulator.ts +3 -5
  64. package/lib/rpc/rpc-client.ts +259 -247
  65. package/lib/rpc/rpc-message-handler.ts +7 -7
  66. package/lib/types.ts +24 -24
  67. package/lib/utils.ts +181 -23
  68. package/package.json +3 -7
  69. package/scripts/common.mjs +42 -37
  70. package/scripts/web_inspector_proxy.mjs +3 -5
@@ -1,6 +1,6 @@
1
1
  import {EventEmitter} from 'node:events';
2
2
  import {log} from '../logger';
3
- import _ from 'lodash';
3
+ import {isPlainObject, truncateString} from '../utils';
4
4
  import {util} from '@appium/support';
5
5
  import type {StringRecord} from '@appium/types';
6
6
 
@@ -106,7 +106,7 @@ export default class RpcMessageHandler extends EventEmitter {
106
106
  try {
107
107
  return JSON.parse(plist.__argument.WIRMessageDataKey.toString('utf8'));
108
108
  } catch (err: any) {
109
- log.error(`Unparseable message data: ${_.truncate(JSON.stringify(plist), {length: 100})}`);
109
+ log.error(`Unparseable message data: ${truncateString(JSON.stringify(plist), 100)}`);
110
110
  throw new Error(`Unable to parse message data: ${err.message}`);
111
111
  }
112
112
  }
@@ -132,7 +132,7 @@ export default class RpcMessageHandler extends EventEmitter {
132
132
  ): Promise<void> {
133
133
  if (msgId) {
134
134
  if (this.listenerCount(msgId)) {
135
- if (_.has(result?.result, 'value')) {
135
+ if (Object.hasOwn(result?.result ?? {}, 'value')) {
136
136
  result = result.result.value;
137
137
  }
138
138
  this.emit(msgId, error, result);
@@ -173,12 +173,12 @@ export default class RpcMessageHandler extends EventEmitter {
173
173
  break;
174
174
  }
175
175
 
176
- if (method && _.startsWith(method, 'Network.')) {
176
+ if (method?.startsWith('Network.')) {
177
177
  // aggregate Network events, and add original method name to the arguments
178
178
  eventNames.push('NetworkEvent');
179
179
  args.push(method);
180
180
  }
181
- if (method && _.startsWith(method, 'Console.')) {
181
+ if (method?.startsWith('Console.')) {
182
182
  // aggregate Console events, and add original method name to the arguments
183
183
  eventNames.push('ConsoleEvent');
184
184
  args.push(method);
@@ -213,7 +213,7 @@ export default class RpcMessageHandler extends EventEmitter {
213
213
  return new Error(message);
214
214
  }
215
215
  if (dataKey.error) {
216
- if (_.isPlainObject(dataKey.error)) {
216
+ if (isPlainObject(dataKey.error)) {
217
217
  const dataKeyError = dataKey.error as DataErrorMessage;
218
218
  const error = new Error(defaultMessage);
219
219
  for (const key of Object.keys(dataKeyError)) {
@@ -242,7 +242,7 @@ export default class RpcMessageHandler extends EventEmitter {
242
242
  if (!dataKey.error) {
243
243
  try {
244
244
  const message = JSON.parse(dataKey.params.message);
245
- msgId = _.isUndefined(message.id) ? '' : String(message.id);
245
+ msgId = message.id === undefined ? '' : String(message.id);
246
246
  method = message.method;
247
247
  result = message.result || message;
248
248
  params = result.params;
package/lib/types.ts CHANGED
@@ -75,10 +75,6 @@ export interface RemoteDebuggerOptions {
75
75
  log?: AppiumLogger;
76
76
  }
77
77
 
78
- interface RemoteDebuggerRealDeviceSpecificOptions {
79
- udid: string;
80
- }
81
-
82
78
  export type RemoteDebuggerRealDeviceOptions = RemoteDebuggerRealDeviceSpecificOptions &
83
79
  RemoteDebuggerOptions;
84
80
 
@@ -110,9 +106,9 @@ export interface RpcClientSimulatorOptions {
110
106
  }
111
107
 
112
108
  export type AppIdKey = string | number;
109
+
113
110
  export type PageIdKey = string | number;
114
111
  export type TargetId = string;
115
-
116
112
  export interface RemoteCommandId {
117
113
  id: string;
118
114
  }
@@ -135,26 +131,8 @@ export interface ProtocolCommandOpts {
135
131
  params: StringRecord;
136
132
  }
137
133
 
138
- type SocketDataKey = Buffer | StringRecord;
139
-
140
- interface RemoteCommandArgument<T extends SocketDataKey> {
141
- WIRSocketDataKey?: T;
142
- WIRConnectionIdentifierKey?: string;
143
- WIRSenderKey?: string;
144
- WIRApplicationIdentifierKey?: AppIdKey;
145
- WIRPageIdentifierKey?: PageIdKey;
146
- WIRMessageDataTypeKey?: string;
147
- WIRDestinationKey?: string;
148
- WIRMessageDataKey?: string;
149
- [key: string]: any;
150
- }
151
-
152
- interface RemoteCommandTemplated<T extends SocketDataKey> {
153
- __argument: RemoteCommandArgument<T>;
154
- __selector: string;
155
- }
156
-
157
134
  export type RawRemoteCommand = RemoteCommandTemplated<StringRecord>;
135
+
158
136
  export type RemoteCommand = RemoteCommandTemplated<Buffer>;
159
137
 
160
138
  /**
@@ -175,3 +153,25 @@ export interface ProvisionalTargetInfo {
175
153
  oldTargetId: string;
176
154
  newTargetId: string;
177
155
  }
156
+ interface RemoteDebuggerRealDeviceSpecificOptions {
157
+ udid: string;
158
+ }
159
+
160
+ type SocketDataKey = Buffer | StringRecord;
161
+
162
+ interface RemoteCommandArgument<T extends SocketDataKey> {
163
+ WIRSocketDataKey?: T;
164
+ WIRConnectionIdentifierKey?: string;
165
+ WIRSenderKey?: string;
166
+ WIRApplicationIdentifierKey?: AppIdKey;
167
+ WIRPageIdentifierKey?: PageIdKey;
168
+ WIRMessageDataTypeKey?: string;
169
+ WIRDestinationKey?: string;
170
+ WIRMessageDataKey?: string;
171
+ [key: string]: any;
172
+ }
173
+
174
+ interface RemoteCommandTemplated<T extends SocketDataKey> {
175
+ __argument: RemoteCommandArgument<T>;
176
+ __selector: string;
177
+ }
package/lib/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
- import _ from 'lodash';
2
1
  import {errorFromMJSONWPStatusCode} from '@appium/base-driver';
3
2
  import {util, node} from '@appium/support';
3
+ import {isDeepStrictEqual} from 'node:util';
4
4
  import nodeFs from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import type {StringRecord} from '@appium/types';
@@ -17,6 +17,149 @@ const ACCEPTED_PAGE_TYPES = [
17
17
  ];
18
18
  export const RESPONSE_LOG_LENGTH = 100;
19
19
 
20
+ /**
21
+ * Error thrown when an async operation exceeds the configured timeout.
22
+ */
23
+ export class TimeoutError extends Error {
24
+ constructor(message: string = 'Operation timed out') {
25
+ super(message);
26
+ this.name = 'TimeoutError';
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Truncates a string to the requested length and appends ellipsis when needed.
32
+ *
33
+ * @param value - The input string.
34
+ * @param length - Maximum output length.
35
+ * @returns The original string when short enough, otherwise a truncated variant.
36
+ */
37
+ export function truncateString(value: string, length: number): string {
38
+ if (value.length <= length) {
39
+ return value;
40
+ }
41
+ return `${value.slice(0, Math.max(0, length - 1))}…`;
42
+ }
43
+
44
+ /**
45
+ * Creates a shallow object where undefined keys from `target` are filled
46
+ * from `defaultsObj`.
47
+ *
48
+ * @param target - The object with priority values.
49
+ * @param defaultsObj - The object providing fallback values.
50
+ * @returns A new object containing merged defaulted values.
51
+ */
52
+ export function defaults<T extends Record<string, any>, U extends Record<string, any>>(
53
+ target: T,
54
+ defaultsObj: U,
55
+ ): T & U {
56
+ const result = {...target} as T & U;
57
+ for (const [key, value] of Object.entries(defaultsObj)) {
58
+ if (result[key as keyof (T & U)] === undefined) {
59
+ (result as any)[key] = value;
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+
65
+ /**
66
+ * Determines whether a value is a plain object.
67
+ *
68
+ * @param value - The value to check.
69
+ * @returns True when the value is a non-null non-array object.
70
+ */
71
+ export function isPlainObject(value: unknown): value is Record<string, any> {
72
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
73
+ return false;
74
+ }
75
+ const prototype = Object.getPrototypeOf(value);
76
+ return prototype === Object.prototype || prototype === null;
77
+ }
78
+
79
+ /**
80
+ * Checks whether a value should be treated as empty.
81
+ *
82
+ * @param value - The value to evaluate.
83
+ * @returns True for nullish values, empty arrays/strings/maps/sets, or empty objects.
84
+ */
85
+ export function isEmpty(value: unknown): boolean {
86
+ if (value == null) {
87
+ return true;
88
+ }
89
+ if (Array.isArray(value) || typeof value === 'string') {
90
+ return value.length === 0;
91
+ }
92
+ if (value instanceof Map || value instanceof Set) {
93
+ return value.size === 0;
94
+ }
95
+ if (isPlainObject(value)) {
96
+ return Object.keys(value).length === 0;
97
+ }
98
+ return false;
99
+ }
100
+
101
+ /**
102
+ * Deduplicates array entries while preserving order.
103
+ *
104
+ * @param items - Items to deduplicate.
105
+ * @returns The input items without duplicates.
106
+ */
107
+ export function uniq<T>(items: T[]): T[] {
108
+ return [...new Set(items)];
109
+ }
110
+
111
+ /**
112
+ * Performs deep strict equality comparison.
113
+ *
114
+ * @param a - First value.
115
+ * @param b - Second value.
116
+ * @returns True when both values are deeply equal.
117
+ */
118
+ export function deepEqual(a: unknown, b: unknown): boolean {
119
+ return isDeepStrictEqual(a, b);
120
+ }
121
+
122
+ /**
123
+ * Returns a promise that resolves after the specified delay.
124
+ *
125
+ * @param ms - Delay in milliseconds.
126
+ * @returns A promise that resolves when the delay expires.
127
+ */
128
+ export function delay(ms: number): Promise<void> {
129
+ return new Promise((resolve) => setTimeout(resolve, ms));
130
+ }
131
+
132
+ /**
133
+ * Wraps a promise with a timeout.
134
+ *
135
+ * @param promise - The promise to resolve.
136
+ * @param timeoutMs - Maximum time to wait in milliseconds.
137
+ * @param message - Optional timeout message.
138
+ * @returns A promise that resolves/rejects with the original promise result, or rejects on timeout.
139
+ */
140
+ export async function withTimeout<T>(
141
+ promise: Promise<T>,
142
+ timeoutMs: number,
143
+ message?: string,
144
+ ): Promise<T> {
145
+ let timeoutId: NodeJS.Timeout | undefined;
146
+ try {
147
+ return await Promise.race([
148
+ promise,
149
+ new Promise<T>((_resolve, reject) => {
150
+ timeoutId = setTimeout(
151
+ () => reject(new TimeoutError(message ?? `Operation timed out after ${timeoutMs}ms`)),
152
+ timeoutMs,
153
+ );
154
+ }),
155
+ ]);
156
+ } finally {
157
+ if (timeoutId) {
158
+ clearTimeout(timeoutId);
159
+ }
160
+ }
161
+ }
162
+
20
163
  /**
21
164
  * Takes a dictionary from the remote debugger and converts it into a more
22
165
  * manageable AppInfo object with understandable keys.
@@ -26,15 +169,16 @@ export const RESPONSE_LOG_LENGTH = 100;
26
169
  */
27
170
  export function appInfoFromDict(dict: Record<string, any>): [string, AppInfo] {
28
171
  const id = dict.WIRApplicationIdentifierKey;
29
- const isProxy = _.isString(dict.WIRIsApplicationProxyKey)
30
- ? dict.WIRIsApplicationProxyKey.toLowerCase() === 'true'
31
- : dict.WIRIsApplicationProxyKey;
172
+ const isProxy =
173
+ typeof dict.WIRIsApplicationProxyKey === 'string'
174
+ ? dict.WIRIsApplicationProxyKey.toLowerCase() === 'true'
175
+ : dict.WIRIsApplicationProxyKey;
32
176
  // automation enabled can be either from the keys
33
177
  // - WIRRemoteAutomationEnabledKey (boolean)
34
178
  // - WIRAutomationAvailabilityKey (string or boolean)
35
179
  let isAutomationEnabled: boolean | string = !!dict.WIRRemoteAutomationEnabledKey;
36
- if (_.has(dict, 'WIRAutomationAvailabilityKey')) {
37
- if (_.isString(dict.WIRAutomationAvailabilityKey)) {
180
+ if (Object.hasOwn(dict, 'WIRAutomationAvailabilityKey')) {
181
+ if (typeof dict.WIRAutomationAvailabilityKey === 'string') {
38
182
  isAutomationEnabled =
39
183
  dict.WIRAutomationAvailabilityKey === 'WIRAutomationAvailabilityUnknown'
40
184
  ? 'Unknown'
@@ -65,16 +209,16 @@ export function appInfoFromDict(dict: Record<string, any>): [string, AppInfo] {
65
209
  */
66
210
  export function pageArrayFromDict(pageDict: StringRecord): Page[] {
67
211
  return (
68
- _.values(pageDict)
212
+ Object.values(pageDict)
69
213
  // count only WIRTypeWeb pages and ignore all others (WIRTypeJavaScript etc)
70
214
  .filter(
71
- (dict) => _.isUndefined(dict.WIRTypeKey) || ACCEPTED_PAGE_TYPES.includes(dict.WIRTypeKey),
215
+ (dict) => dict.WIRTypeKey === undefined || ACCEPTED_PAGE_TYPES.includes(dict.WIRTypeKey),
72
216
  )
73
217
  .map((dict) => ({
74
218
  id: dict.WIRPageIdentifierKey,
75
219
  title: dict.WIRTitleKey,
76
220
  url: dict.WIRURLKey,
77
- isKey: !_.isUndefined(dict.WIRConnectionIdentifierKey),
221
+ isKey: dict.WIRConnectionIdentifierKey !== undefined,
78
222
  }))
79
223
  );
80
224
  }
@@ -89,7 +233,7 @@ export function pageArrayFromDict(pageDict: StringRecord): Page[] {
89
233
  * @returns An array of unique application identifier keys matching the bundle ID.
90
234
  */
91
235
  export function appIdsForBundle(bundleId: string, appDict: AppDict): string[] {
92
- const appIds: string[] = _.toPairs(appDict)
236
+ const appIds: string[] = Object.entries(appDict)
93
237
  .filter(([, data]) => data.bundleId === bundleId)
94
238
  .map(([key]) => key);
95
239
 
@@ -98,7 +242,7 @@ export function appIdsForBundle(bundleId: string, appDict: AppDict): string[] {
98
242
  return appIdsForBundle(WEB_CONTENT_BUNDLE_ID, appDict);
99
243
  }
100
244
 
101
- return _.uniq(appIds);
245
+ return uniq(appIds);
102
246
  }
103
247
 
104
248
  /**
@@ -112,8 +256,8 @@ export function appIdsForBundle(bundleId: string, appDict: AppDict): string[] {
112
256
  */
113
257
  export function checkParams<T extends StringRecord>(params: T): T {
114
258
  // check if all parameters have a value
115
- const errors = _.toPairs(params)
116
- .filter(([, value]) => _.isNil(value))
259
+ const errors = Object.entries(params)
260
+ .filter(([, value]) => value == null)
117
261
  .map(([param]) => param);
118
262
  if (errors.length) {
119
263
  throw new Error(`Missing ${util.pluralize('parameter', errors.length)}: ${errors.join(', ')}`);
@@ -134,7 +278,10 @@ export function simpleStringify(value: any, multiline: boolean = false): string
134
278
  return JSON.stringify(value);
135
279
  }
136
280
 
137
- const cleanValue = removeNoisyProperties(_.clone(value));
281
+ const cleanValue =
282
+ value && (typeof value === 'object' || typeof value === 'function')
283
+ ? removeNoisyProperties(structuredClone(value))
284
+ : value;
138
285
  return multiline ? JSON.stringify(cleanValue, null, 2) : JSON.stringify(cleanValue);
139
286
  }
140
287
 
@@ -149,29 +296,29 @@ export function simpleStringify(value: any, multiline: boolean = false): string
149
296
  * an error status code.
150
297
  */
151
298
  export function convertJavascriptEvaluationResult(res: any): any {
152
- if (_.isUndefined(res)) {
299
+ if (res === undefined) {
153
300
  throw new Error(
154
- `Did not get OK result from remote debugger. Result was: ${_.truncate(simpleStringify(res), {length: RESPONSE_LOG_LENGTH})}`,
301
+ `Did not get OK result from remote debugger. Result was: ${truncateString(simpleStringify(res), RESPONSE_LOG_LENGTH)}`,
155
302
  );
156
- } else if (_.isString(res)) {
303
+ } else if (typeof res === 'string') {
157
304
  try {
158
305
  res = JSON.parse(res);
159
306
  } catch {
160
307
  // we might get a serialized object, but we might not
161
308
  // if we get here, it is just a value
162
309
  }
163
- } else if (!_.isObject(res)) {
310
+ } else if ((typeof res !== 'object' && typeof res !== 'function') || res === null) {
164
311
  throw new Error(`Result has unexpected type: (${typeof res}).`);
165
312
  }
166
313
 
167
- if (res.status && res.status !== 0) {
314
+ if (Object.hasOwn(res, 'status') && res.status !== 0) {
168
315
  // we got some form of error.
169
316
  throw errorFromMJSONWPStatusCode(res.status, res.value.message || res.value);
170
317
  }
171
318
 
172
319
  // with either have an object with a `value` property (even if `null`),
173
320
  // or a plain object
174
- const value = _.has(res, 'value') ? res.value : res;
321
+ const value = Object.hasOwn(res, 'value') ? res.value : res;
175
322
  return removeNoisyProperties(value);
176
323
  }
177
324
 
@@ -182,13 +329,24 @@ export function convertJavascriptEvaluationResult(res: any): any {
182
329
  * @returns The full path to the module root directory.
183
330
  * @throws Error if the module root folder cannot be determined.
184
331
  */
185
- export const getModuleRoot = _.memoize(function getModuleRoot(): string {
332
+ let cachedModuleRoot: string | undefined;
333
+ /**
334
+ * Calculates and memoizes the path to the current module root.
335
+ *
336
+ * @returns The full path to the module root directory.
337
+ * @throws Error if the module root folder cannot be determined.
338
+ */
339
+ export function getModuleRoot(): string {
340
+ if (cachedModuleRoot) {
341
+ return cachedModuleRoot;
342
+ }
186
343
  const root = node.getModuleRootSync(MODULE_NAME, __filename);
187
344
  if (!root) {
188
345
  throw new Error(`Cannot find the root folder of the ${MODULE_NAME} Node.js module`);
189
346
  }
347
+ cachedModuleRoot = root;
190
348
  return root;
191
- });
349
+ }
192
350
 
193
351
  /**
194
352
  * Reads and parses the package.json file from the module root.
@@ -217,7 +375,7 @@ export function canUseWebInspectorShim(platformVersion: string): boolean {
217
375
  * @returns The cleaned object.
218
376
  */
219
377
  function removeNoisyProperties<T>(obj: T): T {
220
- if (_.isObject(obj)) {
378
+ if (obj && typeof obj === 'object') {
221
379
  for (const property of ['ceil', 'clone', 'floor', 'round', 'scale', 'toString']) {
222
380
  delete obj[property];
223
381
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "appium"
6
6
  ],
7
- "version": "15.7.3",
7
+ "version": "15.8.0",
8
8
  "author": "Appium Contributors",
9
9
  "license": "Apache-2.0",
10
10
  "repository": {
@@ -35,11 +35,9 @@
35
35
  "@appium/base-driver": "^10.0.0-rc.1",
36
36
  "@appium/support": "^7.0.0-rc.1",
37
37
  "appium-ios-device": "^3.0.0",
38
- "asyncbox": "^6.1.0",
39
38
  "async-lock": "^1.4.1",
40
- "bluebird": "^3.4.7",
39
+ "asyncbox": "^6.1.0",
41
40
  "glob": "^13.0.0",
42
- "lodash": "^4.17.11",
43
41
  "teen_process": "^4.0.4"
44
42
  },
45
43
  "optionalDependencies": {
@@ -74,8 +72,6 @@
74
72
  "@appium/types": "^1.0.0-rc.1",
75
73
  "@semantic-release/changelog": "^6.0.1",
76
74
  "@semantic-release/git": "^10.0.1",
77
- "@types/bluebird": "^3.5.38",
78
- "@types/lodash": "^4.14.196",
79
75
  "@types/mocha": "^10.0.1",
80
76
  "@types/node": "^25.0.0",
81
77
  "appium-ios-simulator": "^8.0.0",
@@ -87,8 +83,8 @@
87
83
  "mocha-multi-reporters": "^1.5.1",
88
84
  "node-simctl": "^8.0.0",
89
85
  "prettier": "^3.0.0",
90
- "serve-static": "^2.2.0",
91
86
  "semantic-release": "^25.0.2",
87
+ "serve-static": "^2.2.0",
92
88
  "sinon": "^21.0.0",
93
89
  "ts-node": "^10.9.1",
94
90
  "typescript": "^6.0.3"
@@ -40,6 +40,48 @@ const ATOMS_DIRECTORY = path.resolve(WORKING_ROOT_DIR, 'atoms');
40
40
  const LAST_UPDATE_FILE = path.resolve(ATOMS_DIRECTORY, 'lastupdate');
41
41
  let bazelCommand;
42
42
 
43
+ /**
44
+ * Clone the target selenium repository and branch into the temporary directory.
45
+ */
46
+ export async function seleniumClone () {
47
+ await seleniumMkdir();
48
+ await seleniumClean();
49
+ const cloneArgs = (branch) => ([
50
+ 'clone',
51
+ `--branch=${branch}`,
52
+ '--depth=1',
53
+ SELENIUM_GITHUB,
54
+ SELENIUM_DIRECTORY,
55
+ ]);
56
+
57
+ log.info(`Cloning branch '${SELENIUM_BRANCH}' from '${SELENIUM_GITHUB}'`);
58
+ await exec('git', cloneArgs(SELENIUM_BRANCH));
59
+ }
60
+
61
+ /**
62
+ * Builds Selenium atoms and imports them into this repository.
63
+ *
64
+ * @param {boolean} shouldClean - Whether to run `bazel clean` before building.
65
+ */
66
+ export async function importAtoms(shouldClean) {
67
+ await checkBazel();
68
+ await atomsCleanDir();
69
+ if (shouldClean) {
70
+ await atomsClean();
71
+ }
72
+ await atomsMkdir();
73
+ await atomsBuild();
74
+ const bazelOutDir = await getBazelOutDir();
75
+ const atomsDir = path.resolve(bazelOutDir, BAZEL_WD_ATOMS_DIR);
76
+ const atomsInjectDir = path.resolve(bazelOutDir, BAZEL_WD_ATOMS_INJECT_DIR);
77
+ const fragmentsDir = path.resolve(bazelOutDir, BAZEL_FRAGMENTS_DIR);
78
+ await atomsCopyAtoms(fragmentsDir);
79
+ // copy fragments first and atoms later so atoms overwrite fragments
80
+ await atomsCopyAtoms(atomsDir);
81
+ await atomsCopyAtoms(atomsInjectDir);
82
+ await atomsTimestamp();
83
+ }
84
+
43
85
  function getBazelEnv() {
44
86
  // Selenium atoms build does not require Android SDK. If these env vars are set locally,
45
87
  // Bazel may try to auto-configure Android toolchains and fail on host-specific SDK issues.
@@ -66,24 +108,6 @@ async function seleniumClean () {
66
108
  await fs.rimraf(SELENIUM_DIRECTORY);
67
109
  }
68
110
 
69
- /**
70
- * Clone the target selenium repository and branch into the temporary directory.
71
- */
72
- export async function seleniumClone () {
73
- await seleniumMkdir();
74
- await seleniumClean();
75
- const cloneArgs = (branch) => ([
76
- 'clone',
77
- `--branch=${branch}`,
78
- '--depth=1',
79
- SELENIUM_GITHUB,
80
- SELENIUM_DIRECTORY,
81
- ]);
82
-
83
- log.info(`Cloning branch '${SELENIUM_BRANCH}' from '${SELENIUM_GITHUB}'`);
84
- await exec('git', cloneArgs(SELENIUM_BRANCH));
85
- };
86
-
87
111
  /**
88
112
  * Check bazel version if current available bazel version on the host machine
89
113
  * meets Selenium's minimum from `.bazelversion` (newer Bazel is allowed).
@@ -228,23 +252,4 @@ async function atomsTimestamp () {
228
252
  log.info(`Recording Selenium revision in atoms dir`);
229
253
  const {stdout} = await exec('git', ['log', '-n', '1', '--decorate=full'], {cwd: SELENIUM_DIRECTORY});
230
254
  await fs.writeFile(LAST_UPDATE_FILE, Buffer.from(stdout.trimEnd() + '\n'));
231
- }
232
-
233
- export async function importAtoms(shouldClean) {
234
- await checkBazel();
235
- await atomsCleanDir();
236
- if (shouldClean) {
237
- await atomsClean();
238
- }
239
- await atomsMkdir();
240
- await atomsBuild();
241
- const bazelOutDir = await getBazelOutDir();
242
- const atomsDir = path.resolve(bazelOutDir, BAZEL_WD_ATOMS_DIR);
243
- const atomsInjectDir = path.resolve(bazelOutDir, BAZEL_WD_ATOMS_INJECT_DIR);
244
- const fragmentsDir = path.resolve(bazelOutDir, BAZEL_FRAGMENTS_DIR);
245
- await atomsCopyAtoms(fragmentsDir);
246
- // copy fragments first and atoms later so atoms overwrite fragments
247
- await atomsCopyAtoms(atomsDir);
248
- await atomsCopyAtoms(atomsInjectDir);
249
- await atomsTimestamp();
250
255
  };
@@ -1,9 +1,7 @@
1
1
  /* eslint-disable no-console */
2
2
  import { SubProcess } from 'teen_process';
3
3
  import { plist, util } from '@appium/support';
4
- import B from 'bluebird';
5
4
  import { getSimulator } from 'appium-ios-simulator';
6
- import _ from 'lodash';
7
5
 
8
6
 
9
7
  async function getSocket (udid) {
@@ -83,8 +81,8 @@ async function startSoCat (socket) {
83
81
  }
84
82
  });
85
83
 
86
- const prom = new B(function (resolve) {
87
- proc.on('exit', function () {
84
+ const prom = new Promise((resolve) => {
85
+ proc.on('exit', () => {
88
86
  resolve('done');
89
87
  });
90
88
  });
@@ -95,7 +93,7 @@ async function startSoCat (socket) {
95
93
  }
96
94
 
97
95
  async function main () {
98
- const udid = _.last(process.argv);
96
+ const udid = process.argv.at(-1);
99
97
  const s = await getSocket(udid);
100
98
  console.log('Simulator web inspector socket:', s);
101
99
  await startSoCat(s);