appium-mac2-driver 3.2.0 → 3.2.2

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.
@@ -10,6 +10,12 @@ import { SubProcess, exec } from 'teen_process';
10
10
  import { waitForCondition } from 'asyncbox';
11
11
  import { checkPortStatus } from 'portscanner';
12
12
  import { execSync } from 'child_process';
13
+ import type {
14
+ HTTPMethod,
15
+ HTTPBody,
16
+ ProxyResponse,
17
+ ProxyOptions,
18
+ } from '@appium/types';
13
19
  import { listChildrenProcessIds, getModuleRoot } from './utils';
14
20
 
15
21
  const log = logger.getLogger('WebDriverAgentMac');
@@ -24,69 +30,55 @@ const STARTUP_TIMEOUT_MS = 120000;
24
30
  const DEFAULT_SYSTEM_PORT = 10100;
25
31
  const DEFAULT_SYSTEM_HOST = '127.0.0.1';
26
32
  const DEFAULT_SHOW_SERVER_LOGS = false;
27
- const RUNNING_PROCESS_IDS = [];
33
+ const RUNNING_PROCESS_IDS: (string | number)[] = [];
28
34
  const RECENT_UPGRADE_TIMESTAMP_PATH = path.join('.appium', 'webdriveragent_mac', 'upgrade.time');
29
35
  const RECENT_MODULE_VERSION_ITEM_NAME = 'recentWdaModuleVersion';
30
36
 
31
-
32
- async function cleanupObsoleteProcesses () {
33
- if (!_.isEmpty(RUNNING_PROCESS_IDS)) {
34
- log.debug(`Cleaning up ${RUNNING_PROCESS_IDS.length} obsolete ` +
35
- util.pluralize('process', RUNNING_PROCESS_IDS.length, false));
36
- try {
37
- await exec('kill', ['-9', ...RUNNING_PROCESS_IDS]);
38
- } catch {}
39
- _.pullAll(RUNNING_PROCESS_IDS, RUNNING_PROCESS_IDS);
40
- }
37
+ export interface SessionOptions {
38
+ reqBasePath?: string;
41
39
  }
42
40
 
43
- process.once('exit', () => {
44
- if (!_.isEmpty(RUNNING_PROCESS_IDS)) {
45
- try {
46
- execSync(`kill -9 ${RUNNING_PROCESS_IDS.join(' ')}`);
47
- } catch {}
48
- _.pullAll(RUNNING_PROCESS_IDS, RUNNING_PROCESS_IDS);
49
- }
50
- });
51
-
52
-
53
41
  export class WDAMacProxy extends JWProxy {
54
- /** @type {boolean|undefined} */
55
- didProcessExit;
42
+ public didProcessExit: boolean = false;
56
43
 
57
- async proxyCommand (url, method, body = null) {
44
+ override async proxyCommand(
45
+ url: string,
46
+ method: HTTPMethod,
47
+ body: HTTPBody = null,
48
+ ): Promise<[ProxyResponse, HTTPBody]> {
58
49
  if (this.didProcessExit) {
59
50
  throw new errors.InvalidContextError(
60
51
  `'${method} ${url}' cannot be proxied to Mac2 Driver server because ` +
61
- 'its process is not running (probably crashed). Check the Appium log for more details');
52
+ 'its process is not running (probably crashed). Check the Appium log for more details',
53
+ );
62
54
  }
63
55
  return await super.proxyCommand(url, method, body);
64
56
  }
65
57
  }
66
58
 
67
59
  class WDAMacProcess {
68
- constructor () {
69
- this.showServerLogs = DEFAULT_SHOW_SERVER_LOGS;
70
- this.port = DEFAULT_SYSTEM_PORT;
71
- this.host = DEFAULT_SYSTEM_HOST;
72
- this.bootstrapRoot = DEFAULT_WDA_ROOT;
73
- this.proc = null;
74
- }
60
+ public port: number = DEFAULT_SYSTEM_PORT;
61
+ public host: string = DEFAULT_SYSTEM_HOST;
62
+ public bootstrapRoot: string = DEFAULT_WDA_ROOT;
63
+ public proc: SubProcess | null = null;
64
+ private _showServerLogs: boolean = DEFAULT_SHOW_SERVER_LOGS;
75
65
 
76
- get isRunning () {
66
+ get isRunning (): boolean {
77
67
  return !!(this.proc?.isRunning);
78
68
  }
79
69
 
80
- get pid () {
70
+ get pid (): number | null {
81
71
  return this.isRunning && this.proc ? this.proc.pid : null;
82
72
  }
83
73
 
84
- async listChildrenPids () {
74
+ async listChildrenPids (): Promise<string[]> {
85
75
  return this.pid ? (await listChildrenProcessIds(this.pid)) : [];
86
76
  }
87
77
 
88
- async cleanupProjectIfFresh () {
89
- const packageInfo = JSON.parse(await fs.readFile(path.join(getModuleRoot(), 'package.json'), 'utf8'));
78
+ async cleanupProjectIfFresh (): Promise<void> {
79
+ const packageInfo = JSON.parse(
80
+ await fs.readFile(path.join(getModuleRoot(), 'package.json'), 'utf8')
81
+ ) as { name: string; version: string };
90
82
  const box = strongbox(packageInfo.name);
91
83
  let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
92
84
  if (!boxItem) {
@@ -97,7 +89,7 @@ class WDAMacProcess {
97
89
  // TODO: to switch from a hardcoded file path to the strongbox usage.
98
90
  try {
99
91
  boxItem = await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, '1.5.4');
100
- } catch (e) {
92
+ } catch (e: any) {
101
93
  log.warn(`The actual module version cannot be persisted: ${e.message}`);
102
94
  return;
103
95
  }
@@ -105,7 +97,7 @@ class WDAMacProcess {
105
97
  log.info('There is no need to perform the project cleanup. A fresh install has been detected');
106
98
  try {
107
99
  await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
108
- } catch (e) {
100
+ } catch (e: any) {
109
101
  log.warn(`The actual module version cannot be persisted: ${e.message}`);
110
102
  }
111
103
  return;
@@ -115,7 +107,7 @@ class WDAMacProcess {
115
107
  let recentModuleVersion = await boxItem.read();
116
108
  try {
117
109
  recentModuleVersion = util.coerceVersion(recentModuleVersion, true);
118
- } catch (e) {
110
+ } catch (e: any) {
119
111
  log.warn(`The persisted module version string has been damaged: ${e.message}`);
120
112
  log.info(`Updating it to '${packageInfo.version}' assuming the project cleanup is not needed`);
121
113
  await boxItem.write(packageInfo.version);
@@ -139,39 +131,17 @@ class WDAMacProcess {
139
131
  ];
140
132
  await exec(XCODEBUILD, args, {cwd: this.bootstrapRoot});
141
133
  await boxItem.write(packageInfo.version);
142
- } catch (e) {
134
+ } catch (e: any) {
143
135
  log.warn(`Cannot perform project cleanup. Original error: ${e.stderr || e.message}`);
144
136
  }
145
137
  }
146
138
 
147
- hasSameOpts ({ showServerLogs, systemPort, systemHost, bootstrapRoot }) {
148
- if (_.isBoolean(showServerLogs) && this.showServerLogs !== showServerLogs
149
- || _.isNil(showServerLogs) && this.showServerLogs !== DEFAULT_SHOW_SERVER_LOGS) {
150
- return false;
151
- }
152
- if (systemPort && this.port !== systemPort
153
- || !systemPort && this.port !== DEFAULT_SYSTEM_PORT) {
154
- return false;
155
- }
156
- if (systemHost && this.host !== systemHost
157
- || !systemHost && this.host !== DEFAULT_SYSTEM_HOST) {
158
- return false;
159
- }
160
- if (bootstrapRoot && this.bootstrapRoot !== bootstrapRoot
161
- || !bootstrapRoot && this.bootstrapRoot !== DEFAULT_WDA_ROOT) {
162
- return false;
163
- }
164
-
165
- return true;
166
- }
167
-
168
- async init (opts = {}) {
169
- // @ts-ignore TODO: Make opts typed
139
+ async init (opts: WDAMacProcessInitOptions = {}): Promise<boolean> {
170
140
  if (this.isRunning && this.hasSameOpts(opts)) {
171
141
  return false;
172
142
  }
173
143
 
174
- this.showServerLogs = opts.showServerLogs ?? this.showServerLogs;
144
+ this._showServerLogs = opts.showServerLogs ?? this._showServerLogs;
175
145
  this.port = opts.systemPort ?? this.port;
176
146
  this.host = opts.systemHost ?? this.host;
177
147
  this.bootstrapRoot = opts.bootstrapRoot ?? this.bootstrapRoot;
@@ -185,7 +155,7 @@ class WDAMacProcess {
185
155
  await this.kill();
186
156
  await cleanupObsoleteProcesses();
187
157
 
188
- let xcodebuild;
158
+ let xcodebuild: string;
189
159
  try {
190
160
  xcodebuild = await fs.which(XCODEBUILD);
191
161
  } catch {
@@ -198,7 +168,7 @@ class WDAMacProcess {
198
168
 
199
169
  log.debug(`Using ${this.host} as server host`);
200
170
  log.debug(`Using port ${this.port}`);
201
- const isPortBusy = async () => (await checkPortStatus(this.port, this.host)) === 'open';
171
+ const isPortBusy = async (): Promise<boolean> => (await checkPortStatus(this.port, this.host)) === 'open';
202
172
  if (await isPortBusy()) {
203
173
  log.warn(`The port #${this.port} at ${this.host} is busy. ` +
204
174
  `Assuming it is an obsolete WDA server instance and ` +
@@ -214,7 +184,7 @@ class WDAMacProcess {
214
184
  waitMs: 3000,
215
185
  intervalMs: 100,
216
186
  });
217
- } catch (e) {
187
+ } catch (e: any) {
218
188
  log.warn(`Did not know how to terminate the process at ${this.host}:${this.port}: ${e.message}. ` +
219
189
  `Perhaps, it is not a WDA server, which is hogging the port?`);
220
190
  throw new Error(`The port #${this.port} at ${this.host} is busy. ` +
@@ -239,13 +209,13 @@ class WDAMacProcess {
239
209
  cwd: this.bootstrapRoot,
240
210
  env,
241
211
  });
242
- if (!this.showServerLogs) {
212
+ if (!this._showServerLogs) {
243
213
  log.info(`Mac2Driver host process logging is disabled. ` +
244
214
  `All the ${XCODEBUILD} output is going to be suppressed. ` +
245
215
  `Set the 'showServerLogs' capability to 'true' if this is an undesired behavior`);
246
216
  }
247
217
  this.proc.on('output', (stdout, stderr) => {
248
- if (!this.showServerLogs) {
218
+ if (!this._showServerLogs) {
249
219
  return;
250
220
  }
251
221
 
@@ -262,7 +232,7 @@ class WDAMacProcess {
262
232
  return true;
263
233
  }
264
234
 
265
- async stop () {
235
+ async stop (): Promise<void> {
266
236
  if (!this.isRunning) {
267
237
  return;
268
238
  }
@@ -276,7 +246,7 @@ class WDAMacProcess {
276
246
  await this.proc?.stop('SIGTERM', 3000);
277
247
  }
278
248
 
279
- async kill () {
249
+ async kill (): Promise<void> {
280
250
  if (!this.isRunning) {
281
251
  return;
282
252
  }
@@ -291,115 +261,66 @@ class WDAMacProcess {
291
261
  await this.proc?.stop('SIGKILL');
292
262
  } catch {}
293
263
  }
294
- }
295
-
296
- export class WDAMacServer {
297
- /** @type {WDAMacProxy} */
298
- proxy;
299
-
300
- constructor () {
301
- this.process = null;
302
- this.serverStartupTimeoutMs = STARTUP_TIMEOUT_MS;
303
- // @ts-ignore this is ok
304
- this.proxy = null;
305
264
 
306
- // To handle if the WDAMac server is proxying requests to a remote WDAMac app instance
307
- this.isProxyingToRemoteServer = false;
308
- }
309
-
310
- async isProxyReady (throwOnExit = true) {
311
- if (!this.proxy) {
265
+ private hasSameOpts (opts: WDAMacProcessInitOptions): boolean {
266
+ const { showServerLogs, systemPort, systemHost, bootstrapRoot } = opts;
267
+ if (_.isBoolean(showServerLogs) && this._showServerLogs !== showServerLogs
268
+ || _.isNil(showServerLogs) && this._showServerLogs !== DEFAULT_SHOW_SERVER_LOGS) {
312
269
  return false;
313
270
  }
314
-
315
- try {
316
- await this.proxy.command('/status', 'GET');
317
- return true;
318
- } catch (err) {
319
- if (throwOnExit && this.proxy.didProcessExit) {
320
- throw new Error(err.message);
321
- }
271
+ if (systemPort && this.port !== systemPort
272
+ || !systemPort && this.port !== DEFAULT_SYSTEM_PORT) {
322
273
  return false;
323
274
  }
324
- }
325
-
326
-
327
- /**
328
- * @typedef {Object} ProxyProperties
329
- *
330
- * @property {string} scheme - The scheme proxy to.
331
- * @property {string} host - The host name proxy to.
332
- * @property {number} port - The port number proxy to.
333
- * @property {string} path - The path proxy to.
334
- */
335
-
336
- /**
337
- * Returns proxy information where WDAMacServer proxy to.
338
- *
339
- * @param {Object} caps - The capabilities in the session.
340
- * @return {ProxyProperties}
341
- * @throws Error if 'webDriverAgentMacUrl' had invalid URL
342
- */
343
- parseProxyProperties (caps) {
344
- let scheme = 'http';
345
- if (!caps.webDriverAgentMacUrl) {
346
- return {
347
- scheme,
348
- host: (this.process?.host ?? caps.systemHost) ?? DEFAULT_SYSTEM_HOST,
349
- port: (this.process?.port ?? caps.systemPort) ?? DEFAULT_SYSTEM_PORT,
350
- path: ''
351
- };
275
+ if (systemHost && this.host !== systemHost
276
+ || !systemHost && this.host !== DEFAULT_SYSTEM_HOST) {
277
+ return false;
352
278
  }
353
-
354
- let parsedUrl;
355
- try {
356
- parsedUrl = new url.URL(caps.webDriverAgentMacUrl);
357
- } catch (e) {
358
- throw new Error(`webDriverAgentMacUrl, '${caps.webDriverAgentMacUrl}', ` +
359
- `in the capabilities is invalid. ${e.message}`);
279
+ if (bootstrapRoot && this.bootstrapRoot !== bootstrapRoot
280
+ || !bootstrapRoot && this.bootstrapRoot !== DEFAULT_WDA_ROOT) {
281
+ return false;
360
282
  }
361
283
 
362
- const { protocol, hostname, port, pathname } = parsedUrl;
363
- if (_.isString(protocol)) {
364
- scheme = protocol.split(':')[0];
284
+ return true;
285
+ }
286
+ }
287
+
288
+ export class WDAMacServer {
289
+ private _proxy: WDAMacProxy | null = null;
290
+ private _process: WDAMacProcess | null = null;
291
+ private _serverStartupTimeoutMs: number = STARTUP_TIMEOUT_MS;
292
+ private _isProxyingToRemoteServer: boolean = false;
293
+
294
+ get proxy (): WDAMacProxy {
295
+ if (!this._proxy) {
296
+ throw new Error('Proxy is not initialized. Did you call startSession()?');
365
297
  }
366
- return {
367
- scheme,
368
- host: hostname ?? DEFAULT_SYSTEM_HOST,
369
- port: _.isEmpty(port) ? DEFAULT_SYSTEM_PORT : _.parseInt(port),
370
- path: pathname === '/' ? '' : pathname
371
- };
298
+ return this._proxy;
372
299
  }
373
300
 
374
- /**
375
- *
376
- * @param {import('@appium/types').StringRecord} caps
377
- * @param {SessionOptions} [opts={}]
378
- */
379
- async startSession (caps, opts = {}) {
380
- this.serverStartupTimeoutMs = caps.serverStartupTimeout ?? this.serverStartupTimeoutMs;
301
+ async startSession (caps: StartSessionCapabilities, opts: SessionOptions = {}): Promise<void> {
302
+ this._serverStartupTimeoutMs = caps.serverStartupTimeout ?? this._serverStartupTimeoutMs;
381
303
 
382
- this.isProxyingToRemoteServer = !!caps.webDriverAgentMacUrl;
304
+ this._isProxyingToRemoteServer = !!caps.webDriverAgentMacUrl;
383
305
 
384
- let wasProcessInitNecessary;
385
- if (this.isProxyingToRemoteServer) {
386
- if (this.process) {
387
- await this.process.kill();
306
+ let wasProcessInitNecessary: boolean;
307
+ if (this._isProxyingToRemoteServer) {
308
+ if (this._process) {
309
+ await this._process.kill();
388
310
  await cleanupObsoleteProcesses();
389
- this.process = null;
311
+ this._process = null;
390
312
  }
391
-
392
313
  wasProcessInitNecessary = false;
393
314
  } else {
394
- if (!this.process) {
395
- this.process = new WDAMacProcess();
315
+ if (!this._process) {
316
+ this._process = new WDAMacProcess();
396
317
  }
397
- wasProcessInitNecessary = await this.process.init(caps);
318
+ wasProcessInitNecessary = await this._process.init(caps);
398
319
  }
399
320
 
400
- if (wasProcessInitNecessary || this.isProxyingToRemoteServer || !this.proxy) {
321
+ if (wasProcessInitNecessary || this._isProxyingToRemoteServer || !this._proxy) {
401
322
  const {scheme, host, port, path} = this.parseProxyProperties(caps);
402
- const proxyOpts = {
323
+ const proxyOpts: ProxyOptions = {
403
324
  scheme,
404
325
  server: host,
405
326
  port,
@@ -409,13 +330,13 @@ export class WDAMacServer {
409
330
  if (caps.reqBasePath) {
410
331
  proxyOpts.reqBasePath = opts.reqBasePath;
411
332
  }
412
- this.proxy = new WDAMacProxy(proxyOpts);
413
- this.proxy.didProcessExit = false;
333
+ this._proxy = new WDAMacProxy(proxyOpts);
334
+ this._proxy.didProcessExit = false;
414
335
 
415
- if (this.process?.proc) {
416
- this.process.proc.on('exit', () => {
417
- if (this.proxy) {
418
- this.proxy.didProcessExit = true;
336
+ if (this._process?.proc) {
337
+ this._process.proc.on('exit', () => {
338
+ if (this._proxy) {
339
+ this._proxy.didProcessExit = true;
419
340
  }
420
341
  });
421
342
  }
@@ -423,19 +344,19 @@ export class WDAMacServer {
423
344
  const timer = new timing.Timer().start();
424
345
  try {
425
346
  await waitForCondition(async () => await this.isProxyReady(), {
426
- waitMs: this.serverStartupTimeoutMs,
347
+ waitMs: this._serverStartupTimeoutMs,
427
348
  intervalMs: 1000,
428
349
  });
429
- } catch (e) {
430
- if (this.process?.isRunning) {
350
+ } catch (e: any) {
351
+ if (this._process?.isRunning) {
431
352
  // avoid "frozen" processes,
432
- await this.process.kill();
353
+ await this._process.kill();
433
354
  }
434
355
  if (/Condition unmet/.test(e.message)) {
435
- const msg = this.isProxyingToRemoteServer
436
- ? `No response from '${scheme}://${host}:${port}${path}' within ${this.serverStartupTimeoutMs}ms timeout.` +
356
+ const msg = this._isProxyingToRemoteServer
357
+ ? `No response from '${scheme}://${host}:${port}${path}' within ${this._serverStartupTimeoutMs}ms timeout.` +
437
358
  `Please make sure the remote server is running and accessible by Appium`
438
- : `Mac2Driver server is not listening within ${this.serverStartupTimeoutMs}ms timeout. ` +
359
+ : `Mac2Driver server is not listening within ${this._serverStartupTimeoutMs}ms timeout. ` +
439
360
  `Try to increase the value of 'serverStartupTimeout' capability, check the server logs ` +
440
361
  `and make sure the ${XCODEBUILD} host process could be started manually from a terminal`;
441
362
  throw new Error(msg);
@@ -443,18 +364,20 @@ export class WDAMacServer {
443
364
  throw e;
444
365
  }
445
366
 
446
- if (this.process) {
447
- const pid = this.process.pid;
448
- const childrenPids = await this.process.listChildrenPids();
449
- RUNNING_PROCESS_IDS.push(...childrenPids, pid);
450
- this.process.proc?.on('exit', () => void _.pull(RUNNING_PROCESS_IDS, pid));
367
+ if (this._process) {
368
+ const pid = this._process.pid;
369
+ const childrenPids = await this._process.listChildrenPids();
370
+ if (pid !== null) {
371
+ RUNNING_PROCESS_IDS.push(...childrenPids, pid);
372
+ this._process.proc?.on('exit', () => void _.pull(RUNNING_PROCESS_IDS, pid));
373
+ }
451
374
  log.info(`The host process is ready within ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
452
375
  }
453
376
  } else {
454
377
  log.info('The host process has already been listening. Proceeding with session creation');
455
378
  }
456
379
 
457
- await this.proxy.command('/session', 'POST', {
380
+ await this._proxy.command('/session', 'POST', {
458
381
  capabilities: {
459
382
  firstMatch: [{}],
460
383
  alwaysMatch: caps,
@@ -462,27 +385,119 @@ export class WDAMacServer {
462
385
  });
463
386
  }
464
387
 
465
- async stopSession () {
466
- if (!this.isProxyingToRemoteServer && !(this.process?.isRunning)) {
388
+ async stopSession (): Promise<void> {
389
+ if (!this._isProxyingToRemoteServer && !(this._process?.isRunning)) {
467
390
  log.info(`Mac2Driver session cannot be stopped, because the server is not running`);
468
391
  return;
469
392
  }
470
393
 
471
- if (this.proxy?.sessionId) {
394
+ if (this._proxy?.sessionId) {
472
395
  try {
473
- await this.proxy.command(`/session/${this.proxy.sessionId}`, 'DELETE');
474
- } catch (e) {
396
+ await this._proxy.command(`/session/${this._proxy.sessionId}`, 'DELETE');
397
+ } catch (e: any) {
475
398
  log.info(`Mac2Driver session cannot be deleted. Original error: ${e.message}`);
476
399
  }
477
400
  }
478
401
  }
402
+
403
+ private async isProxyReady (throwOnExit = true): Promise<boolean> {
404
+ if (!this._proxy) {
405
+ return false;
406
+ }
407
+
408
+ try {
409
+ await this._proxy.command('/status', 'GET');
410
+ return true;
411
+ } catch (err: any) {
412
+ if (throwOnExit && this._proxy.didProcessExit) {
413
+ throw new Error(err.message);
414
+ }
415
+ return false;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Returns proxy information where WDAMacServer proxy to.
421
+ *
422
+ * @param caps - The capabilities in the session.
423
+ * @return ProxyProperties
424
+ * @throws Error if 'webDriverAgentMacUrl' had invalid URL
425
+ */
426
+ private parseProxyProperties (caps: StartSessionCapabilities): ProxyProperties {
427
+ let scheme = 'http';
428
+ if (!caps.webDriverAgentMacUrl) {
429
+ return {
430
+ scheme,
431
+ host: (this._process?.host ?? caps.systemHost) ?? DEFAULT_SYSTEM_HOST,
432
+ port: (this._process?.port ?? caps.systemPort) ?? DEFAULT_SYSTEM_PORT,
433
+ path: ''
434
+ };
435
+ }
436
+
437
+ let parsedUrl: url.URL;
438
+ try {
439
+ parsedUrl = new url.URL(caps.webDriverAgentMacUrl);
440
+ } catch (e: any) {
441
+ throw new Error(`webDriverAgentMacUrl, '${caps.webDriverAgentMacUrl}', ` +
442
+ `in the capabilities is invalid. ${e.message}`);
443
+ }
444
+
445
+ const { protocol, hostname, port, pathname } = parsedUrl;
446
+ if (_.isString(protocol)) {
447
+ scheme = protocol.split(':')[0];
448
+ }
449
+ return {
450
+ scheme,
451
+ host: hostname ?? DEFAULT_SYSTEM_HOST,
452
+ port: _.isEmpty(port) ? DEFAULT_SYSTEM_PORT : _.parseInt(port),
453
+ path: pathname === '/' ? '' : pathname
454
+ };
455
+ }
456
+ }
457
+
458
+ export const WDA_MAC_SERVER = new WDAMacServer();
459
+
460
+ // Private functions
461
+ async function cleanupObsoleteProcesses (): Promise<void> {
462
+ if (!_.isEmpty(RUNNING_PROCESS_IDS)) {
463
+ log.debug(`Cleaning up ${RUNNING_PROCESS_IDS.length} obsolete ` +
464
+ util.pluralize('process', RUNNING_PROCESS_IDS.length, false));
465
+ try {
466
+ await exec('kill', ['-9', ...RUNNING_PROCESS_IDS.map(String)]);
467
+ } catch {}
468
+ _.pullAll(RUNNING_PROCESS_IDS, RUNNING_PROCESS_IDS);
469
+ }
479
470
  }
480
471
 
481
- const WDA_MAC_SERVER = new WDAMacServer();
472
+ process.once('exit', () => {
473
+ if (!_.isEmpty(RUNNING_PROCESS_IDS)) {
474
+ try {
475
+ execSync(`kill -9 ${RUNNING_PROCESS_IDS.map(String).join(' ')}`);
476
+ } catch {}
477
+ _.pullAll(RUNNING_PROCESS_IDS, RUNNING_PROCESS_IDS);
478
+ }
479
+ });
480
+
481
+ // Private type definitions
482
+ interface WDAMacProcessInitOptions {
483
+ showServerLogs?: boolean;
484
+ systemPort?: number;
485
+ systemHost?: string;
486
+ bootstrapRoot?: string;
487
+ }
482
488
 
483
- export default WDA_MAC_SERVER;
489
+ interface ProxyProperties {
490
+ scheme: string;
491
+ host: string;
492
+ port: number;
493
+ path: string;
494
+ }
484
495
 
485
- /**
486
- * @typedef {Object} SessionOptions
487
- * @property {string} [reqBasePath]
488
- */
496
+ interface StartSessionCapabilities {
497
+ webDriverAgentMacUrl?: string;
498
+ systemHost?: string;
499
+ systemPort?: number;
500
+ serverStartupTimeout?: number;
501
+ reqBasePath?: string;
502
+ [key: string]: unknown;
503
+ }