detox 20.34.4 → 20.34.5

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 (43) hide show
  1. package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4-sources.jar → 20.34.5/detox-20.34.5-sources.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.pom → 20.34.5/detox-20.34.5.pom} +1 -1
  7. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5.pom.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5.pom.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5.pom.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.34.5/detox-20.34.5.pom.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  12. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  13. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  14. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  15. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  16. package/Detox-ios-framework.tbz +0 -0
  17. package/Detox-ios-src.tbz +0 -0
  18. package/Detox-ios-xcuitest.tbz +0 -0
  19. package/local-cli/utils/frameworkUtils.js +2 -3
  20. package/package.json +4 -4
  21. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +28 -14
  22. package/src/devices/common/drivers/android/exec/ADB.js +14 -4
  23. package/src/devices/common/drivers/android/exec/BinaryExec.js +8 -7
  24. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +6 -0
  25. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +6 -7
  26. package/src/ios/XCUITestRunner.js +2 -3
  27. package/src/utils/assertArgument.js +3 -1
  28. package/src/utils/childProcess/exec.js +9 -2
  29. package/src/utils/childProcess/spawn.js +33 -15
  30. package/src/utils/environment.js +10 -11
  31. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4-sources.jar.md5 +0 -1
  32. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4-sources.jar.sha1 +0 -1
  33. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4-sources.jar.sha256 +0 -1
  34. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4-sources.jar.sha512 +0 -1
  35. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4.pom.md5 +0 -1
  36. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4.pom.sha1 +0 -1
  37. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4.pom.sha256 +0 -1
  38. package/Detox-android/com/wix/detox/20.34.4/detox-20.34.4.pom.sha512 +0 -1
  39. /package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.aar → 20.34.5/detox-20.34.5.aar} +0 -0
  40. /package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.aar.md5 → 20.34.5/detox-20.34.5.aar.md5} +0 -0
  41. /package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.aar.sha1 → 20.34.5/detox-20.34.5.aar.sha1} +0 -0
  42. /package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.aar.sha256 → 20.34.5/detox-20.34.5.aar.sha256} +0 -0
  43. /package/Detox-android/com/wix/detox/{20.34.4/detox-20.34.4.aar.sha512 → 20.34.5/detox-20.34.5.aar.sha512} +0 -0
@@ -0,0 +1 @@
1
+ bd14839975954a26f5a5de90ea5db58d
@@ -0,0 +1 @@
1
+ 4a95b5deea127463d33a0082724efa15c0219b7b
@@ -0,0 +1 @@
1
+ 334fcb0435039628b166d5d24a9bc16d548458acdbace630b63a64f8e8392cf5
@@ -0,0 +1 @@
1
+ 7e465d127ecc42d3dd2f3965cccecbf9925daaca5f1aef7e91004d14fa3b6ab0e7853fa7343b75123c75b6a803734f8ca5ac9d7441e1c69e310aa76637d3f3fd
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox</artifactId>
6
- <version>20.34.4</version>
6
+ <version>20.34.5</version>
7
7
  <packaging>aar</packaging>
8
8
  <name>Detox</name>
9
9
  <description>Gray box end-to-end testing and automation library for mobile apps</description>
@@ -0,0 +1 @@
1
+ a21b9bbeda17018156da809bbd4ad378
@@ -0,0 +1 @@
1
+ e6fd98f4bd1aa47112a571668f6848d2c3c242bd
@@ -0,0 +1 @@
1
+ 6e9772775917f0c4dfb8b7da2399efd534c54bbfd83c356bcf8b888936b73bed
@@ -0,0 +1 @@
1
+ b850844b3cacf4524dba60a84d81dbc2630bc028b29aa3a22822ae79986ec47879e9f32ad3492b13a5a86943a388854f0b3f437985d33a730f2fc5418fe021bc
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.34.4</latest>
7
- <release>20.34.4</release>
6
+ <latest>20.34.5</latest>
7
+ <release>20.34.5</release>
8
8
  <versions>
9
- <version>20.34.4</version>
9
+ <version>20.34.5</version>
10
10
  </versions>
11
- <lastUpdated>20250228153149</lastUpdated>
11
+ <lastUpdated>20250311134145</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 06c32f673954b1d53e564d3718cd4944
1
+ 124aa88e915e9b18fd8a733a6b941d15
@@ -1 +1 @@
1
- 422cf2392817b37bfbffbfcf9a6053133404bb08
1
+ 9049aefa5e582d75a4f797598a69c570698aa159
@@ -1 +1 @@
1
- 396411db488a866223fb2a3008e903ad29270fc3899fb0bccb6502063a9824fd
1
+ ac5eced7982a7c3f738b02c2431dadc151c7c34ca8bc5ad543fb8ab44133501a
@@ -1 +1 @@
1
- 5247250ffabcf87485dca59afa70c250325b70763c968d7380b5d280cd4fac8115c7dc650ec0d3f6762317cd5fb298c2f2e22b1d0887798fa5363d9ab0a98e53
1
+ a11b2a21800e4ea7748f5cb337929eba7c3e1070057306ea31821d6f18c256522c46262370f85f07d5e098d6bd4eb4f2c5ac23c0752c06f53a891f0cd6e9cdc4
Binary file
package/Detox-ios-src.tbz CHANGED
Binary file
Binary file
@@ -1,13 +1,12 @@
1
1
  const os = require('os');
2
2
  const path = require('path');
3
3
 
4
- const { spawn } = require('child-process-promise');
5
4
  const fs = require('fs-extra');
6
5
 
7
6
  const detox = require('../../internals');
7
+ const { spawnAndLog } = require('../../src/utils/childProcess');
8
8
  const { getFrameworkDirPath, getXCUITestRunnerDirPath } = require('../../src/utils/environment');
9
9
 
10
-
11
10
  const frameworkBuildScript = '../../scripts/build_local_framework.ios.sh';
12
11
  const xcuitestBuildScript = '../../scripts/build_local_xcuitest.ios.sh';
13
12
 
@@ -26,7 +25,7 @@ async function execBuildScript(targetPath, scriptPath, descriptor) {
26
25
  const scriptFullPath = path.join(__dirname, scriptPath);
27
26
 
28
27
  try {
29
- await spawn(scriptFullPath, [], { stdio: 'inherit' });
28
+ await spawnAndLog(scriptFullPath, [], { stdio: 'inherit' });
30
29
  } catch (error) {
31
30
  detox.log.error(`Error while building ${descriptor}:\n${error}`);
32
31
  throw error;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "detox",
3
3
  "description": "E2E tests and automation for mobile",
4
- "version": "20.34.4",
4
+ "version": "20.34.5",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -64,7 +64,7 @@
64
64
  "prettier": "^3.1.1",
65
65
  "react-native": "0.76.3",
66
66
  "react-native-codegen": "^0.0.8",
67
- "typescript": "^5.3.3",
67
+ "typescript": "~5.3.3",
68
68
  "wtfnode": "^0.9.1"
69
69
  },
70
70
  "dependencies": {
@@ -73,7 +73,6 @@
73
73
  "bunyan-debug-stream": "^3.1.0",
74
74
  "caf": "^15.0.1",
75
75
  "chalk": "^4.0.0",
76
- "child-process-promise": "^2.2.0",
77
76
  "detox-copilot": "^0.0.27",
78
77
  "execa": "^5.1.1",
79
78
  "find-up": "^5.0.0",
@@ -87,6 +86,7 @@
87
86
  "multi-sort-stream": "^1.0.3",
88
87
  "multipipe": "^4.0.0",
89
88
  "node-ipc": "9.2.1",
89
+ "promisify-child-process": "^4.1.2",
90
90
  "proper-lockfile": "^3.0.2",
91
91
  "resolve-from": "^5.0.0",
92
92
  "sanitize-filename": "^1.6.1",
@@ -119,5 +119,5 @@
119
119
  "browserslist": [
120
120
  "node 14"
121
121
  ],
122
- "gitHead": "ce6e754c352f1670a17ef7560e9e2c1ebb373a20"
122
+ "gitHead": "3ad6fc5da870368e43d5b09b72c4d844b8342ace"
123
123
  }
@@ -31,23 +31,37 @@ function launchEmulatorProcess(emulatorExec, adb, emulatorLaunchCommand) {
31
31
 
32
32
  log = log.child({ child_pid: childProcessPromise.childProcess.pid });
33
33
 
34
- adb.waitForDevice(emulatorLaunchCommand.adbName).then(() => childProcessPromise._cpResolve());
34
+ // Create a deferred promise that resolves when the device is ready
35
+ let resolveEmulatorReady;
36
+ const emulatorReadyPromise = new Promise(resolve => {
37
+ resolveEmulatorReady = resolve;
38
+ });
35
39
 
36
- return childProcessPromise.then(() => true).catch((err) => {
37
- detach();
40
+ // Wait for the device to be ready
41
+ adb.waitForDevice(emulatorLaunchCommand.adbName).then(() => {
42
+ resolveEmulatorReady();
43
+ });
38
44
 
39
- if (childProcessOutput.includes(`There's another emulator instance running with the current AVD`)) {
40
- return false;
41
- }
45
+ // Use Promise.race to resolve with the first one to complete - either the emulator process exits
46
+ // or the emulator device is ready
47
+ return Promise.race([childProcessPromise, emulatorReadyPromise])
48
+ .then(() => true)
49
+ .catch((err) => {
50
+ detach();
42
51
 
43
- log.error({ event: 'SPAWN_FAIL', error: true, err }, err.message);
44
- log.error({ event: 'SPAWN_FAIL', stderr: true }, childProcessOutput);
45
- throw err;
46
- }).then((coldBoot) => {
47
- detach();
48
- log.debug({ event: 'SPAWN_SUCCESS', stdout: true }, childProcessOutput);
49
- return coldBoot;
50
- });
52
+ if (childProcessOutput && childProcessOutput.includes(`There's another emulator instance running with the current AVD`)) {
53
+ return false;
54
+ }
55
+
56
+ log.error({ event: 'SPAWN_FAIL', error: true, err }, err.message);
57
+ log.error({ event: 'SPAWN_FAIL', stderr: true }, childProcessOutput);
58
+ throw err;
59
+ })
60
+ .then((coldBoot) => {
61
+ detach();
62
+ log.debug({ event: 'SPAWN_SUCCESS', stdout: true }, childProcessOutput);
63
+ return coldBoot;
64
+ });
51
65
  }
52
66
 
53
67
  module.exports = { launchEmulatorProcess };
@@ -8,11 +8,19 @@ const { escape } = require('../../../../../utils/pipeCommands');
8
8
  const DeviceHandle = require('../tools/DeviceHandle');
9
9
  const EmulatorHandle = require('../tools/EmulatorHandle');
10
10
 
11
- const INSTALL_TIMEOUT = 45000;
11
+ const DEFAULT_EXEC_OPTIONS = {
12
+ retries: 1,
13
+ };
14
+ const DEFAULT_INSTALL_OPTIONS = {
15
+ timeout: 60000,
16
+ retries: 3,
17
+ };
12
18
 
13
19
  class ADB {
14
20
  constructor() {
15
21
  this._cachedApiLevels = new Map();
22
+ this.defaultExecOptions = DEFAULT_EXEC_OPTIONS;
23
+ this.installOptions = DEFAULT_INSTALL_OPTIONS;
16
24
  this.adbBin = getAdbPath();
17
25
  }
18
26
 
@@ -113,7 +121,7 @@ class ADB {
113
121
  const command = (apiLvl >= 23)
114
122
  ? `install -r -g -t ${apkPath}`
115
123
  : `install -rg ${apkPath}`;
116
- const result = await this.adbCmdSpawned(deviceId, command, { timeout: INSTALL_TIMEOUT, retries: 3 });
124
+ const result = await this.adbCmdSpawned(deviceId, command, this.installOptions);
117
125
 
118
126
  const [failure] = (result.stdout || '').match(/^Failure \[.*\]$/m) || [];
119
127
  if (failure) {
@@ -129,7 +137,7 @@ class ADB {
129
137
  const command = (apiLvl >= 23)
130
138
  ? `pm install -r -g -t ${path}`
131
139
  : `pm install -rg ${path}`;
132
- return this.shellSpawned(deviceId, command, { timeout: INSTALL_TIMEOUT, retries: 3 });
140
+ return this.shellSpawned(deviceId, command, this.installOptions);
133
141
  }
134
142
 
135
143
  async uninstall(deviceId, appId) {
@@ -353,7 +361,7 @@ class ADB {
353
361
  const serial = `${deviceId ? `-s ${deviceId}` : ''}`;
354
362
  const cmd = `"${this.adbBin}" ${serial} ${params}`;
355
363
  const _options = {
356
- retries: 1,
364
+ ...this.defaultExecOptions,
357
365
  ...options,
358
366
  };
359
367
  return execWithRetriesAndLogs(cmd, _options);
@@ -364,8 +372,10 @@ class ADB {
364
372
  const serial = deviceId ? ['-s', deviceId] : [];
365
373
  const _flags = [...serial, ...flags];
366
374
  const _spawnOptions = {
375
+ ...this.defaultExecOptions,
367
376
  ...spawnOptions,
368
377
  capture: ['stdout'],
378
+ encoding: 'utf8',
369
379
  };
370
380
  return spawnWithRetriesAndLogs(this.adbBin, _flags, _spawnOptions);
371
381
  }
@@ -1,7 +1,4 @@
1
- // @ts-nocheck
2
- const spawn = require('child-process-promise').spawn;
3
-
4
- const exec = require('../../../../../utils/childProcess').execWithRetriesAndLogs;
1
+ const { execAsync, spawnAndLog } = require('../../../../../utils/childProcess');
5
2
 
6
3
  class ExecCommand {
7
4
  toString() {
@@ -27,15 +24,19 @@ class BinaryExec {
27
24
  }
28
25
 
29
26
  async exec(command) {
30
- return (await exec(`"${this.binary}" ${command._getArgsString()}`)).stdout;
27
+ return await execAsync(`"${this.binary}" ${command._getArgsString()}`);
31
28
  }
32
29
 
33
30
  spawn(command, stdout, stderr) {
34
- return spawn(this.binary, command._getArgs(), { detached: true, stdio: ['ignore', stdout, stderr] });
31
+ return spawnAndLog(this.binary, command._getArgs(), {
32
+ detached: true,
33
+ encoding: 'utf8',
34
+ stdio: ['ignore', stdout, stderr]
35
+ });
35
36
  }
36
37
  }
37
38
 
38
39
  module.exports = {
39
40
  ExecCommand,
40
- BinaryExec,
41
+ BinaryExec
41
42
  };
@@ -19,6 +19,12 @@ class GenyCloudDriver extends AndroidDriver {
19
19
  constructor(deps, { adbName, name }) {
20
20
  super(deps, { adbName });
21
21
 
22
+ // Make ADB more resilient to network latency and connection hiccups
23
+ this.adb.defaultExecOptions = {
24
+ retries: 5,
25
+ interval: 3000,
26
+ backoff: 'linear',
27
+ };
22
28
  this._instanceName = name;
23
29
  }
24
30
 
@@ -1,13 +1,14 @@
1
1
  // @ts-nocheck
2
2
  const path = require('path');
3
3
 
4
- const exec = require('child-process-promise').exec;
5
4
  const _ = require('lodash');
6
5
 
6
+
7
7
  const temporaryPath = require('../../../../artifacts/utils/temporaryPath');
8
8
  const DetoxRuntimeError = require('../../../../errors/DetoxRuntimeError');
9
9
  const XCUITestRunner = require('../../../../ios/XCUITestRunner');
10
10
  const { assertTraceDescription } = require('../../../../utils/assertArgument');
11
+ const { execAsync } = require('../../../../utils/childProcess');
11
12
  const getAbsoluteBinaryPath = require('../../../../utils/getAbsoluteBinaryPath');
12
13
  const { actionDescription } = require('../../../../utils/invocationTraceDescriptions');
13
14
  const log = require('../../../../utils/logger').child({ cat: 'device' });
@@ -16,7 +17,6 @@ const traceInvocationCall = require('../../../../utils/traceInvocationCall').bin
16
17
 
17
18
  const IosDriver = require('./IosDriver');
18
19
 
19
-
20
20
  /**
21
21
  * @typedef SimulatorDriverDeps { DeviceDriverDeps }
22
22
  * @property applesimutils { AppleSimUtils }
@@ -69,8 +69,7 @@ class SimulatorDriver extends IosDriver {
69
69
  async getBundleIdFromBinary(appPath) {
70
70
  appPath = getAbsoluteBinaryPath(appPath);
71
71
  try {
72
- const result = await exec(`/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" "${path.join(appPath, 'Info.plist')}"`);
73
- const bundleId = _.trim(result.stdout);
72
+ const bundleId = await execAsync(`/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" "${path.join(appPath, 'Info.plist')}"`);
74
73
  if (_.isEmpty(bundleId)) {
75
74
  throw new Error();
76
75
  }
@@ -141,7 +140,7 @@ class SimulatorDriver extends IosDriver {
141
140
  const xcuitestRunner = new XCUITestRunner({ runtimeDevice: { id: this.getExternalId(), _bundleId } });
142
141
  let x = point?.x ?? 100;
143
142
  let y = point?.y ?? 100;
144
- let _pressDuration = pressDuration ? (pressDuration / 1000) : 1;
143
+ let _pressDuration = pressDuration ? pressDuration / 1000 : 1;
145
144
  const traceDescription = actionDescription.longPress({ x, y }, _pressDuration);
146
145
  return this.withAction(xcuitestRunner, 'coordinateLongPress', traceDescription, x.toString(), y.toString(), _pressDuration.toString());
147
146
  }
@@ -210,7 +209,7 @@ class SimulatorDriver extends IosDriver {
210
209
  await this.emitter.emit('createExternalArtifact', {
211
210
  pluginId: 'screenshot',
212
211
  artifactName: screenshotName || path.basename(tempPath, '.png'),
213
- artifactPath: tempPath,
212
+ artifactPath: tempPath
214
213
  });
215
214
 
216
215
  return tempPath;
@@ -223,7 +222,7 @@ class SimulatorDriver extends IosDriver {
223
222
  await this.emitter.emit('createExternalArtifact', {
224
223
  pluginId: 'uiHierarchy',
225
224
  artifactName: artifactName,
226
- artifactPath: viewHierarchyURL,
225
+ artifactPath: viewHierarchyURL
227
226
  });
228
227
 
229
228
  return viewHierarchyURL;
@@ -1,6 +1,5 @@
1
- const { exec } = require('child-process-promise');
2
-
3
1
  const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
2
+ const { execAsync } = require('../utils/childProcess');
4
3
  const environment = require('../utils/environment');
5
4
  const log = require('../utils/logger').child({ cat: 'xcuitest-runner' });
6
5
 
@@ -37,7 +36,7 @@ class XCUITestRunner {
37
36
  `--predicate 'process == "DetoxXCUITestRunner-Runner" && subsystem == "com.wix.DetoxXCUITestRunner.xctrunner"'`);
38
37
 
39
38
  try {
40
- return await exec(`TEST_RUNNER_PARAMS="${base64InvocationParams}" TEST_RUNNER_BUNDLE_ID="${this.runtimeDevice._bundleId}" xcodebuild ${flags.join(' ')}`);
39
+ return await execAsync(`TEST_RUNNER_PARAMS="${base64InvocationParams}" TEST_RUNNER_BUNDLE_ID="${this.runtimeDevice._bundleId}" xcodebuild ${flags.join(' ')}`);
41
40
  } catch (e) {
42
41
  const stdout = e.stdout.toString();
43
42
  const innerError = this.findInnerError(stdout);
@@ -1,7 +1,9 @@
1
+ const _ = require('lodash');
2
+
1
3
  const { DetoxInternalError, DetoxRuntimeError } = require('../errors');
2
4
 
3
5
  function firstEntry(obj) {
4
- return Object.entries(obj)[0];
6
+ return _.entries(obj)[0] || ['value', obj];
5
7
  }
6
8
 
7
9
  function assertType(expectedType) {
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
- const { exec } = require('child-process-promise');
3
2
  const _ = require('lodash');
3
+ const { exec } = require('promisify-child-process');
4
4
 
5
5
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
6
6
  const rootLogger = require('../logger').child({ cat: ['child-process', 'child-process-exec'] });
@@ -8,10 +8,17 @@ const retry = require('../retry');
8
8
 
9
9
  const execsCounter = require('./opsCounter');
10
10
 
11
+ /**
12
+ * Executes a command with retries and logs
13
+ * @param {*} bin - command to execute
14
+ * @param {*} options - options
15
+ * @returns {Promise<import('promisify-child-process').Output>}
16
+ */
11
17
  async function execWithRetriesAndLogs(bin, options = {}) {
12
18
  const {
13
19
  retries = 9,
14
20
  interval = 1000,
21
+ backoff,
15
22
  prefix = null,
16
23
  args = null,
17
24
  timeout,
@@ -30,7 +37,7 @@ async function execWithRetriesAndLogs(bin, options = {}) {
30
37
  try {
31
38
  logger.debug({ event: 'EXEC_CMD' }, `${cmd}`);
32
39
 
33
- await retry({ retries, interval }, async (tryNumber, lastError) => {
40
+ await retry({ retries, interval, backoff }, async (tryNumber, lastError) => {
34
41
  if (statusLogs.trying) {
35
42
  _logExecTrying(logger, statusLogs.trying, tryNumber, lastError);
36
43
  } else if (statusLogs.retrying) {
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
- const { spawn } = require('child-process-promise');
3
2
  const _ = require('lodash');
3
+ const { spawn } = require('promisify-child-process');
4
4
 
5
5
  const rootLogger = require('../logger').child({ cat: ['child-process', 'child-process-spawn'] });
6
6
  const { escape } = require('../pipeCommands');
@@ -8,15 +8,15 @@ const retry = require('../retry');
8
8
 
9
9
  const execsCounter = require('./opsCounter');
10
10
 
11
- function spawnAndLog(binary, flags, options) {
12
- const command = _joinCommandAndFlags(binary, flags);
11
+ function spawnAndLog(binary, args, options) {
12
+ const command = _joinCommandAndArgs(binary, args);
13
13
  const trackingId = execsCounter.inc();
14
14
  const logger = rootLogger.child({ fn: 'spawnAndLog', command, trackingId });
15
- return _spawnAndLog(logger, binary, flags, command, options);
15
+ return _spawnAndLog(logger, binary, args, command, options);
16
16
  }
17
17
 
18
- async function spawnWithRetriesAndLogs(binary, flags, options = {}) {
19
- const command = _joinCommandAndFlags(binary, flags);
18
+ async function spawnWithRetriesAndLogs(binary, args, options = {}) {
19
+ const command = _joinCommandAndArgs(binary, args);
20
20
  const trackingId = execsCounter.inc();
21
21
  const logger = rootLogger.child({ fn: 'spawnWithRetriesAndLogs', command, trackingId });
22
22
  const _options = {
@@ -26,13 +26,15 @@ async function spawnWithRetriesAndLogs(binary, flags, options = {}) {
26
26
  const {
27
27
  retries = 1,
28
28
  interval = 100,
29
+ backoff = 'none',
29
30
  ...spawnOptions
30
31
  } = _options;
31
32
 
32
33
  let result;
33
- await retry({ retries, interval }, async (tryCount, lastError) => {
34
+ await retry({ retries, interval, backoff }, async (tryCount, lastError) => {
34
35
  _logSpawnRetrying(logger, tryCount, lastError);
35
- result = await _spawnAndLog(logger, binary, flags, command, spawnOptions, tryCount);
36
+ result = _spawnAndLog(logger, binary, args, command, spawnOptions, tryCount);
37
+ await result;
36
38
  });
37
39
  return result;
38
40
  }
@@ -66,11 +68,23 @@ async function interruptProcess(childProcessPromise, schedule) {
66
68
  }
67
69
  }
68
70
 
69
- function _spawnAndLog(logger, binary, flags, command, options, tryCount) {
71
+ function _spawnAndLog(logger, binary, args, command, options, tryCount) {
70
72
  const { logLevelPatterns, silent, ...spawnOptions } = { stdio: ['ignore', 'pipe', 'pipe'], ...options };
71
- const cpPromise = spawn(binary, flags, spawnOptions);
73
+ const cpPromise = spawn(binary, args, spawnOptions);
74
+ const childProcess = cpPromise.childProcess = cpPromise;
75
+ const originalThen = cpPromise.then.bind(cpPromise);
76
+ const augmentPromise = (fn) => {
77
+ return typeof fn === 'function'
78
+ ? (result) => fn(Object.assign(result, {
79
+ childProcess,
80
+ exitCode: childProcess.exitCode,
81
+ pid: childProcess.pid
82
+ }))
83
+ : fn;
84
+ };
85
+ cpPromise.then = (onFulfilled, onRejected) => originalThen(augmentPromise(onFulfilled), augmentPromise(onRejected));
86
+ cpPromise.catch = (onRejected) => cpPromise.then(undefined, onRejected);
72
87
 
73
- const { childProcess } = cpPromise;
74
88
  const { exitCode, stdout, stderr } = childProcess;
75
89
 
76
90
  const _logger = logger.child({ cpid: childProcess.pid });
@@ -85,8 +99,12 @@ function _spawnAndLog(logger, binary, flags, command, options, tryCount) {
85
99
  stderr && stderr.on('data', _spawnStderrLoggerFn(_logger, logLevelPatterns));
86
100
  }
87
101
 
102
+ /**
103
+ *
104
+ * @param {import('promisify-child-process').Output} resultOrErr
105
+ */
88
106
  function onEnd(resultOrErr) {
89
- const signal = resultOrErr.childProcess.signalCode || '';
107
+ const signal = resultOrErr.signal || '';
90
108
  const { code } = resultOrErr;
91
109
  const action = signal ? `terminated with ${signal}` : `exited with code #${code}`;
92
110
 
@@ -97,11 +115,11 @@ function _spawnAndLog(logger, binary, flags, command, options, tryCount) {
97
115
  return cpPromise;
98
116
  }
99
117
 
100
- function _joinCommandAndFlags(command, flags) {
118
+ function _joinCommandAndArgs(command, args) {
101
119
  let result = command;
102
120
 
103
- for (const flag of flags.map(String)) {
104
- result += ' ' + (flag.indexOf(' ') === -1 ? flag : `"${escape.inQuotedString(flag)}"`);
121
+ for (const arg of args.map(String)) {
122
+ result += ' ' + (arg.indexOf(' ') === -1 ? arg : `"${escape.inQuotedString(arg)}"`);
105
123
  }
106
124
 
107
125
  return result;
@@ -3,7 +3,6 @@ const fs = require('fs');
3
3
  const os = require('os');
4
4
  const path = require('path');
5
5
 
6
- const exec = require('child-process-promise').exec;
7
6
  const ini = require('ini');
8
7
  const _ = require('lodash');
9
8
  const _which = require('which');
@@ -11,6 +10,7 @@ const _which = require('which');
11
10
  const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
12
11
 
13
12
  const appdatapath = require('./appdatapath');
13
+ const { execAsync } = require('./childProcess');
14
14
  const fsext = require('./fsext');
15
15
 
16
16
  function which(executable, path) {
@@ -147,8 +147,7 @@ function throwMissingAvdINIError(avdName, avdIniPath) {
147
147
 
148
148
  function throwMissingAvdError(avdName, avdPath, avdIniPath) {
149
149
  throw new DetoxRuntimeError(
150
- `Failed to find AVD ${avdName} directory at path: ${avdPath}\n` +
151
- `Please verify "path" property in the INI file: ${avdIniPath}`
150
+ `Failed to find AVD ${avdName} directory at path: ${avdPath}\n` + `Please verify "path" property in the INI file: ${avdIniPath}`
152
151
  );
153
152
  }
154
153
 
@@ -169,7 +168,9 @@ function throwSdkIntegrityError(errMessage) {
169
168
  }
170
169
 
171
170
  function throwMissingGmsaasError() {
172
- throw new DetoxRuntimeError(`Failed to locate Genymotion's gmsaas executable. Please add it to your $PATH variable!\nPATH is currently set to: ${process.env.PATH}`);
171
+ throw new DetoxRuntimeError(
172
+ `Failed to locate Genymotion's gmsaas executable. Please add it to your $PATH variable!\nPATH is currently set to: ${process.env.PATH}`
173
+ );
173
174
  }
174
175
 
175
176
  const getDetoxVersion = _.once(() => {
@@ -178,11 +179,9 @@ const getDetoxVersion = _.once(() => {
178
179
 
179
180
  const getBuildFolderName = _.once(async () => {
180
181
  const detoxVersion = getDetoxVersion();
181
- const xcodeVersion = await exec('xcodebuild -version').then(result => result.stdout.trim());
182
+ const xcodeVersion = await execAsync('xcodebuild -version');
182
183
 
183
- return crypto.createHash('sha1')
184
- .update(`${detoxVersion}\n${xcodeVersion}\n`)
185
- .digest('hex');
184
+ return crypto.createHash('sha1').update(`${detoxVersion}\n${xcodeVersion}\n`).digest('hex');
186
185
  });
187
186
 
188
187
  const getFrameworkDirPath = `${DETOX_LIBRARY_ROOT_PATH}/ios/framework`;
@@ -197,8 +196,8 @@ const getXCUITestRunnerDirPath = `${DETOX_LIBRARY_ROOT_PATH}/ios/xcuitest-runner
197
196
  const getXCUITestRunnerPath = _.once(async () => {
198
197
  const buildFolder = await getBuildFolderName();
199
198
  const derivedDataPath = `${getXCUITestRunnerDirPath}/${buildFolder}`;
200
- const xctestrunPath = await exec(`find ${derivedDataPath} -name "*.xctestrun" -print -quit`)
201
- .then(result => result.stdout.trim());
199
+ const command = `find ${derivedDataPath} -name "*.xctestrun" -print -quit`;
200
+ const xctestrunPath = await execAsync(command);
202
201
 
203
202
  if (!xctestrunPath) {
204
203
  throw new DetoxRuntimeError(`Failed to find .xctestrun file in ${derivedDataPath}`);
@@ -246,5 +245,5 @@ module.exports = {
246
245
  getDetoxLockFilePath,
247
246
  getDeviceRegistryPath,
248
247
  getLastFailedTestsPath,
249
- getHomeDir,
248
+ getHomeDir
250
249
  };
@@ -1 +0,0 @@
1
- 5f5196f635a4832725da896810590789
@@ -1 +0,0 @@
1
- c62b14e7a401961458f13dd67b850ca25d69b077
@@ -1 +0,0 @@
1
- 0cdc662aabf9d7ace8a67dfee962534e768b4dcf5a581e1ceab52574abf1db94
@@ -1 +0,0 @@
1
- 934054ada43e380895eab4232738acbfd8811e21cb8d17d86a64d125ee72c77a614ebe64f0ab2a1fb0be2c2024f740d07d6bbe5d8314a7bf5dba9254b34b691d
@@ -1 +0,0 @@
1
- 9bf85b779cbf0003d3d05d73be00bd75
@@ -1 +0,0 @@
1
- c15e6faf08b4bfa7527827c75632779cf0cd5c39
@@ -1 +0,0 @@
1
- 026e8bfe7dcf8aa652df44a12a390ba1bdc300b44d0533205e27ea2ed17f96cb
@@ -1 +0,0 @@
1
- fe59aad8ba547a5ba93c59094b1126f70d670a2e236a06f708936791363b38fe7169fbe541b3bc2d6336d5c2799135b625fd42d68426a54f3cbd39c5134fb4fc