appium-webdriveragent 11.1.4 → 11.1.6
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.
- package/CHANGELOG.md +12 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +14 -5
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationApp.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_1.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_2.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_3.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentLib.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentLib_tvOS.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner-nodebug.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +1 -1
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner_tvOS.xcscheme +1 -1
- package/WebDriverAgentLib/Info.plist +2 -2
- package/build/lib/check-dependencies.d.ts.map +1 -1
- package/build/lib/check-dependencies.js +6 -3
- package/build/lib/check-dependencies.js.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/no-session-proxy.d.ts.map +1 -1
- package/build/lib/no-session-proxy.js +1 -1
- package/build/lib/no-session-proxy.js.map +1 -1
- package/build/lib/types.d.ts.map +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +8 -9
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webdriveragent.d.ts.map +1 -1
- package/build/lib/webdriveragent.js +21 -20
- package/build/lib/webdriveragent.js.map +1 -1
- package/build/lib/xcodebuild.d.ts.map +1 -1
- package/build/lib/xcodebuild.js +16 -19
- package/build/lib/xcodebuild.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/check-dependencies.ts +20 -14
- package/lib/constants.ts +0 -1
- package/lib/logger.ts +1 -1
- package/lib/no-session-proxy.ts +5 -7
- package/lib/types.ts +6 -1
- package/lib/utils.ts +80 -52
- package/lib/webdriveragent.ts +189 -134
- package/lib/xcodebuild.ts +62 -54
- package/package.json +3 -2
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {fs} from '@appium/support';
|
|
2
|
+
import {exec} from 'teen_process';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
} from './
|
|
7
|
-
import { BOOTSTRAP_PATH } from './utils';
|
|
8
|
-
import type { XcodeBuild } from './xcodebuild';
|
|
4
|
+
import {WDA_SCHEME, SDK_SIMULATOR, WDA_RUNNER_APP} from './constants';
|
|
5
|
+
import {BOOTSTRAP_PATH} from './utils';
|
|
6
|
+
import type {XcodeBuild} from './xcodebuild';
|
|
9
7
|
|
|
10
|
-
async function buildWDASim
|
|
8
|
+
async function buildWDASim(): Promise<void> {
|
|
11
9
|
const args = [
|
|
12
|
-
'-project',
|
|
13
|
-
'
|
|
14
|
-
'-
|
|
10
|
+
'-project',
|
|
11
|
+
path.join(BOOTSTRAP_PATH, 'WebDriverAgent.xcodeproj'),
|
|
12
|
+
'-scheme',
|
|
13
|
+
WDA_SCHEME,
|
|
14
|
+
'-sdk',
|
|
15
|
+
SDK_SIMULATOR,
|
|
15
16
|
'CODE_SIGN_IDENTITY=""',
|
|
16
17
|
'CODE_SIGNING_REQUIRED="NO"',
|
|
17
18
|
'GCC_TREAT_WARNINGS_AS_ERRORS=0',
|
|
@@ -19,16 +20,21 @@ async function buildWDASim (): Promise<void> {
|
|
|
19
20
|
await exec('xcodebuild', args);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export async function bundleWDASim
|
|
23
|
+
export async function bundleWDASim(xcodebuild: XcodeBuild): Promise<string> {
|
|
23
24
|
const derivedDataPath = await xcodebuild.retrieveDerivedDataPath();
|
|
24
25
|
if (!derivedDataPath) {
|
|
25
26
|
throw new Error('Cannot retrieve the path to the Xcode derived data folder');
|
|
26
27
|
}
|
|
27
|
-
const wdaBundlePath = path.join(
|
|
28
|
+
const wdaBundlePath = path.join(
|
|
29
|
+
derivedDataPath,
|
|
30
|
+
'Build',
|
|
31
|
+
'Products',
|
|
32
|
+
'Debug-iphonesimulator',
|
|
33
|
+
WDA_RUNNER_APP,
|
|
34
|
+
);
|
|
28
35
|
if (await fs.exists(wdaBundlePath)) {
|
|
29
36
|
return wdaBundlePath;
|
|
30
37
|
}
|
|
31
38
|
await buildWDASim();
|
|
32
39
|
return wdaBundlePath;
|
|
33
40
|
}
|
|
34
|
-
|
package/lib/constants.ts
CHANGED
package/lib/logger.ts
CHANGED
package/lib/no-session-proxy.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
1
|
+
import {JWProxy} from '@appium/base-driver';
|
|
2
|
+
import type {ProxyOptions} from '@appium/types';
|
|
4
3
|
|
|
5
4
|
export class NoSessionProxy extends JWProxy {
|
|
6
|
-
constructor
|
|
5
|
+
constructor(opts: ProxyOptions = {}) {
|
|
7
6
|
super(opts);
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
override getUrlForProxy
|
|
9
|
+
override getUrlForProxy(url: string): string {
|
|
11
10
|
if (url === '') {
|
|
12
11
|
url = '/';
|
|
13
12
|
}
|
|
14
13
|
const proxyBase = `${this.scheme}://${this.server}:${this.port}${this.base}`;
|
|
15
14
|
let remainingUrl = '';
|
|
16
|
-
if (
|
|
15
|
+
if (new RegExp('^/').test(url)) {
|
|
17
16
|
remainingUrl = url;
|
|
18
17
|
} else {
|
|
19
18
|
throw new Error(`Did not know what to do with url '${url}'`);
|
|
@@ -22,4 +21,3 @@ export class NoSessionProxy extends JWProxy {
|
|
|
22
21
|
return proxyBase + remainingUrl;
|
|
23
22
|
}
|
|
24
23
|
}
|
|
25
|
-
|
package/lib/types.ts
CHANGED
|
@@ -21,7 +21,12 @@ export interface WDASettings {
|
|
|
21
21
|
defaultAlertAction?: 'accept' | 'dismiss';
|
|
22
22
|
acceptAlertButtonSelector?: string;
|
|
23
23
|
dismissAlertButtonSelector?: string;
|
|
24
|
-
screenshotOrientation?:
|
|
24
|
+
screenshotOrientation?:
|
|
25
|
+
| 'auto'
|
|
26
|
+
| 'portrait'
|
|
27
|
+
| 'portraitUpsideDown'
|
|
28
|
+
| 'landscapeRight'
|
|
29
|
+
| 'landscapeLeft';
|
|
25
30
|
waitForIdleTimeout?: number;
|
|
26
31
|
animationCoolOffTimeout?: number;
|
|
27
32
|
maxTypingFrequency?: number;
|
package/lib/utils.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import path, {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import {fs, plist} from '@appium/support';
|
|
2
|
+
import {exec, SubProcess} from 'teen_process';
|
|
3
|
+
import path, {dirname} from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
import {log} from './logger';
|
|
6
6
|
import _ from 'lodash';
|
|
7
|
-
import {
|
|
7
|
+
import {PLATFORM_NAME_TVOS} from './constants';
|
|
8
8
|
import B from 'bluebird';
|
|
9
9
|
import _fs from 'node:fs';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import type {
|
|
10
|
+
import {waitForCondition} from 'asyncbox';
|
|
11
|
+
import {arch} from 'node:os';
|
|
12
|
+
import type {DeviceInfo} from './types';
|
|
13
13
|
|
|
14
14
|
// Get current filename - works in both CommonJS and ESM
|
|
15
15
|
const currentFilename =
|
|
@@ -25,14 +25,16 @@ const currentDirname = dirname(currentFilename);
|
|
|
25
25
|
* @returns {string} The full path to module root
|
|
26
26
|
* @throws {Error} If the current module root folder cannot be determined
|
|
27
27
|
*/
|
|
28
|
-
const getModuleRoot = _.memoize(function getModuleRoot
|
|
28
|
+
const getModuleRoot = _.memoize(function getModuleRoot(): string {
|
|
29
29
|
let currentDir = currentDirname;
|
|
30
30
|
let isAtFsRoot = false;
|
|
31
31
|
while (!isAtFsRoot) {
|
|
32
32
|
const manifestPath = path.join(currentDir, 'package.json');
|
|
33
33
|
try {
|
|
34
|
-
if (
|
|
35
|
-
|
|
34
|
+
if (
|
|
35
|
+
_fs.existsSync(manifestPath) &&
|
|
36
|
+
JSON.parse(_fs.readFileSync(manifestPath, 'utf8')).name === 'appium-webdriveragent'
|
|
37
|
+
) {
|
|
36
38
|
return currentDir;
|
|
37
39
|
}
|
|
38
40
|
} catch {}
|
|
@@ -44,7 +46,7 @@ const getModuleRoot = _.memoize(function getModuleRoot (): string {
|
|
|
44
46
|
|
|
45
47
|
export const BOOTSTRAP_PATH = getModuleRoot();
|
|
46
48
|
|
|
47
|
-
export async function killAppUsingPattern
|
|
49
|
+
export async function killAppUsingPattern(pgrepPattern: string): Promise<void> {
|
|
48
50
|
const signals = [2, 15, 9];
|
|
49
51
|
for (const signal of signals) {
|
|
50
52
|
const matchedPids = await getPIDsUsingPattern(pgrepPattern);
|
|
@@ -62,20 +64,22 @@ export async function killAppUsingPattern (pgrepPattern: string): Promise<void>
|
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
try {
|
|
65
|
-
await waitForCondition(
|
|
66
|
-
|
|
67
|
-
.map((pid) =>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
await waitForCondition(
|
|
68
|
+
async () => {
|
|
69
|
+
const pidCheckPromises = matchedPids.map((pid) =>
|
|
70
|
+
exec('kill', ['-0', pid])
|
|
71
|
+
// the process is still alive
|
|
72
|
+
.then(() => false)
|
|
73
|
+
// the process is dead
|
|
74
|
+
.catch(() => true),
|
|
72
75
|
);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
return (await B.all(pidCheckPromises)).every((x) => x === true);
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
waitMs: 1000,
|
|
80
|
+
intervalMs: 100,
|
|
81
|
+
},
|
|
82
|
+
);
|
|
79
83
|
return;
|
|
80
84
|
} catch {
|
|
81
85
|
// try the next signal
|
|
@@ -88,11 +92,14 @@ export async function killAppUsingPattern (pgrepPattern: string): Promise<void>
|
|
|
88
92
|
* @param platformName The name of the platorm
|
|
89
93
|
* @returns Return true if the platformName is tvOS
|
|
90
94
|
*/
|
|
91
|
-
export function isTvOS
|
|
95
|
+
export function isTvOS(platformName: string): boolean {
|
|
92
96
|
return _.toLower(platformName) === _.toLower(PLATFORM_NAME_TVOS);
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
export async function setRealDeviceSecurity
|
|
99
|
+
export async function setRealDeviceSecurity(
|
|
100
|
+
keychainPath: string,
|
|
101
|
+
keychainPassword: string,
|
|
102
|
+
): Promise<void> {
|
|
96
103
|
log.debug('Setting security for iOS device');
|
|
97
104
|
await exec('security', ['-v', 'list-keychains', '-s', keychainPath]);
|
|
98
105
|
await exec('security', ['-v', 'unlock-keychain', '-p', keychainPassword, keychainPath]);
|
|
@@ -124,11 +131,15 @@ export interface XctestrunFileArgs {
|
|
|
124
131
|
* or WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator is not found @bootstrapPath,
|
|
125
132
|
* then it will throw a file not found exception
|
|
126
133
|
*/
|
|
127
|
-
export async function setXctestrunFile
|
|
134
|
+
export async function setXctestrunFile(args: XctestrunFileArgs): Promise<string> {
|
|
128
135
|
const {deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort, wdaBindingIP} = args;
|
|
129
136
|
const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath);
|
|
130
137
|
const xctestRunContent = await plist.parsePlistFile(xctestrunFilePath);
|
|
131
|
-
const updateWDAPort = getAdditionalRunContent(
|
|
138
|
+
const updateWDAPort = getAdditionalRunContent(
|
|
139
|
+
deviceInfo.platformName,
|
|
140
|
+
wdaRemotePort,
|
|
141
|
+
wdaBindingIP,
|
|
142
|
+
);
|
|
132
143
|
const newXctestRunContent = _.merge(xctestRunContent, updateWDAPort);
|
|
133
144
|
await plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true);
|
|
134
145
|
|
|
@@ -142,16 +153,20 @@ export async function setXctestrunFile (args: XctestrunFileArgs): Promise<string
|
|
|
142
153
|
* @param wdaBindingIP - The IP address to bind to. If not given, it binds to all interfaces.
|
|
143
154
|
* @return returns a runner object which has USE_PORT and optionally USE_IP
|
|
144
155
|
*/
|
|
145
|
-
export function getAdditionalRunContent
|
|
156
|
+
export function getAdditionalRunContent(
|
|
157
|
+
platformName: string,
|
|
158
|
+
wdaRemotePort: number | string,
|
|
159
|
+
wdaBindingIP?: string,
|
|
160
|
+
): Record<string, any> {
|
|
146
161
|
const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`;
|
|
147
162
|
return {
|
|
148
163
|
[runner]: {
|
|
149
164
|
EnvironmentVariables: {
|
|
150
165
|
// USE_PORT must be 'string'
|
|
151
166
|
USE_PORT: `${wdaRemotePort}`,
|
|
152
|
-
...(wdaBindingIP ? {
|
|
153
|
-
}
|
|
154
|
-
}
|
|
167
|
+
...(wdaBindingIP ? {USE_IP: wdaBindingIP} : {}),
|
|
168
|
+
},
|
|
169
|
+
},
|
|
155
170
|
};
|
|
156
171
|
}
|
|
157
172
|
|
|
@@ -161,7 +176,11 @@ export function getAdditionalRunContent (platformName: string, wdaRemotePort: nu
|
|
|
161
176
|
* @param sdkVersion - The Xcode SDK version of OS.
|
|
162
177
|
* @param bootstrapPath - The folder path containing xctestrun file.
|
|
163
178
|
*/
|
|
164
|
-
export async function getXctestrunFilePath
|
|
179
|
+
export async function getXctestrunFilePath(
|
|
180
|
+
deviceInfo: DeviceInfo,
|
|
181
|
+
sdkVersion: string,
|
|
182
|
+
bootstrapPath: string,
|
|
183
|
+
): Promise<string> {
|
|
165
184
|
// First try the SDK path, for Xcode 10 (at least)
|
|
166
185
|
const sdkBased: [string, string] = [
|
|
167
186
|
path.resolve(bootstrapPath, `${deviceInfo.udid}_${sdkVersion}.xctestrun`),
|
|
@@ -178,7 +197,10 @@ export async function getXctestrunFilePath (deviceInfo: DeviceInfo, sdkVersion:
|
|
|
178
197
|
log.info(`Using '${filePath}' as xctestrun file`);
|
|
179
198
|
return filePath;
|
|
180
199
|
}
|
|
181
|
-
const originalXctestrunFile = path.resolve(
|
|
200
|
+
const originalXctestrunFile = path.resolve(
|
|
201
|
+
bootstrapPath,
|
|
202
|
+
getXctestrunFileName(deviceInfo, version),
|
|
203
|
+
);
|
|
182
204
|
if (await fs.exists(originalXctestrunFile)) {
|
|
183
205
|
// If this is first time run for given device, then first generate xctestrun file for device.
|
|
184
206
|
// We need to have a xctestrun file **per device** because we cant not have same wda port for all devices.
|
|
@@ -190,19 +212,18 @@ export async function getXctestrunFilePath (deviceInfo: DeviceInfo, sdkVersion:
|
|
|
190
212
|
|
|
191
213
|
throw new Error(
|
|
192
214
|
`If you are using 'useXctestrunFile' capability then you ` +
|
|
193
|
-
|
|
194
|
-
|
|
215
|
+
`need to have a xctestrun file (expected: ` +
|
|
216
|
+
`'${path.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, sdkVersion))}')`,
|
|
195
217
|
);
|
|
196
218
|
}
|
|
197
219
|
|
|
198
|
-
|
|
199
220
|
/**
|
|
200
221
|
* Return the name of xctestrun file
|
|
201
222
|
* @param deviceInfo
|
|
202
223
|
* @param version - The Xcode SDK version of OS.
|
|
203
224
|
* @return returns xctestrunFilePath for given device
|
|
204
225
|
*/
|
|
205
|
-
export function getXctestrunFileName
|
|
226
|
+
export function getXctestrunFileName(deviceInfo: DeviceInfo, version: string): string {
|
|
206
227
|
const archSuffix = deviceInfo.isRealDevice
|
|
207
228
|
? `os${version}-arm64`
|
|
208
229
|
: `simulator${version}-${arch() === 'arm64' ? 'arm64' : 'x86_64'}`;
|
|
@@ -212,7 +233,10 @@ export function getXctestrunFileName (deviceInfo: DeviceInfo, version: string):
|
|
|
212
233
|
/**
|
|
213
234
|
* Ensures the process is killed after the timeout
|
|
214
235
|
*/
|
|
215
|
-
export async function killProcess
|
|
236
|
+
export async function killProcess(
|
|
237
|
+
name: string,
|
|
238
|
+
proc: SubProcess | null | undefined,
|
|
239
|
+
): Promise<void> {
|
|
216
240
|
if (!proc || !proc.isRunning) {
|
|
217
241
|
return;
|
|
218
242
|
}
|
|
@@ -245,16 +269,16 @@ export async function killProcess (name: string, proc: SubProcess | null | undef
|
|
|
245
269
|
/**
|
|
246
270
|
* Generate a random integer in range [low, high). `low` is inclusive and `high` is exclusive.
|
|
247
271
|
*/
|
|
248
|
-
export function randomInt
|
|
272
|
+
export function randomInt(low: number, high: number): number {
|
|
249
273
|
return Math.floor(Math.random() * (high - low) + low);
|
|
250
274
|
}
|
|
251
275
|
|
|
252
276
|
/**
|
|
253
277
|
* Retrieves WDA upgrade timestamp. The manifest only gets modified on package upgrade.
|
|
254
278
|
*/
|
|
255
|
-
export async function getWDAUpgradeTimestamp
|
|
279
|
+
export async function getWDAUpgradeTimestamp(): Promise<number | null> {
|
|
256
280
|
const packageManifest = path.resolve(getModuleRoot(), 'package.json');
|
|
257
|
-
if (!await fs.exists(packageManifest)) {
|
|
281
|
+
if (!(await fs.exists(packageManifest))) {
|
|
258
282
|
return null;
|
|
259
283
|
}
|
|
260
284
|
const {mtime} = await fs.stat(packageManifest);
|
|
@@ -264,7 +288,7 @@ export async function getWDAUpgradeTimestamp (): Promise<number | null> {
|
|
|
264
288
|
/**
|
|
265
289
|
* Kills running XCTest processes for the particular device.
|
|
266
290
|
*/
|
|
267
|
-
export async function resetTestProcesses
|
|
291
|
+
export async function resetTestProcesses(udid: string, isSimulator: boolean): Promise<void> {
|
|
268
292
|
const processPatterns = [`xcodebuild.*${udid}`];
|
|
269
293
|
if (isSimulator) {
|
|
270
294
|
processPatterns.push(`${udid}.*XCTRunner`);
|
|
@@ -288,12 +312,15 @@ export async function resetTestProcesses (udid: string, isSimulator: boolean): P
|
|
|
288
312
|
* from the resulting array.
|
|
289
313
|
* @returns - the list of matched process ids.
|
|
290
314
|
*/
|
|
291
|
-
export async function getPIDsListeningOnPort
|
|
315
|
+
export async function getPIDsListeningOnPort(
|
|
316
|
+
port: string | number,
|
|
317
|
+
filteringFunc: ((cmdline: string) => boolean | Promise<boolean>) | null = null,
|
|
318
|
+
): Promise<string[]> {
|
|
292
319
|
const result: string[] = [];
|
|
293
320
|
try {
|
|
294
321
|
// This only works since Mac OS X El Capitan
|
|
295
322
|
const {stdout} = await exec('lsof', ['-ti', `tcp:${port}`]);
|
|
296
|
-
result.push(...
|
|
323
|
+
result.push(...stdout.trim().split(/\n+/));
|
|
297
324
|
} catch (e: any) {
|
|
298
325
|
if (e.code !== 1) {
|
|
299
326
|
// code 1 means no processes. Other errors need reporting
|
|
@@ -322,21 +349,22 @@ export async function getPIDsListeningOnPort (port: string | number, filteringFu
|
|
|
322
349
|
|
|
323
350
|
// Private functions
|
|
324
351
|
|
|
325
|
-
async function getPIDsUsingPattern
|
|
352
|
+
async function getPIDsUsingPattern(pattern: string): Promise<string[]> {
|
|
326
353
|
const args = [
|
|
327
354
|
'-if', // case insensitive, full cmdline match
|
|
328
355
|
pattern,
|
|
329
356
|
];
|
|
330
357
|
try {
|
|
331
358
|
const {stdout} = await exec('pgrep', args);
|
|
332
|
-
return stdout
|
|
359
|
+
return stdout
|
|
360
|
+
.split(/\s+/)
|
|
333
361
|
.map((x) => parseInt(x, 10))
|
|
334
362
|
.filter(_.isInteger)
|
|
335
363
|
.map((x) => `${x}`);
|
|
336
364
|
} catch (err: any) {
|
|
337
|
-
log.debug(
|
|
365
|
+
log.debug(
|
|
366
|
+
`'pgrep ${args.join(' ')}' didn't detect any matching processes. Return code: ${err.code}`,
|
|
367
|
+
);
|
|
338
368
|
return [];
|
|
339
369
|
}
|
|
340
370
|
}
|
|
341
|
-
|
|
342
|
-
|