detox 20.0.1-breaking.new-global-lifecycle.0 → 20.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. package/Detox-android/com/wix/detox/{20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-javadoc.jar → 20.0.1/detox-20.0.1-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-sources.jar → 20.0.1/detox-20.0.1-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.pom → 20.0.1/detox-20.0.1.pom} +1 -7
  17. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.1/detox-20.0.1.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/README.md +1 -1
  29. package/android/build.gradle +12 -7
  30. package/android/detox/build.gradle +13 -9
  31. package/android/detox/proguard-rules-app.pro +6 -0
  32. package/android/detox/proguard-rules.pro +3 -0
  33. package/android/detox/publishing.gradle +27 -27
  34. package/android/detox/src/full/java/com/wix/detox/DetoxCrashHandler.kt +1 -1
  35. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  36. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +1 -1
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/IdlingResourceDescription.kt +19 -13
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +33 -30
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +7 -27
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +1 -11
  43. package/android/detox/src/main/java/com/wix/detox/common/TextFileReader.kt +1 -1
  44. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/DetoxMultiTapSpec.kt +4 -3
  45. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +61 -0
  46. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +3 -11
  47. package/index.d.ts +198 -57
  48. package/internals.d.ts +219 -45
  49. package/local-cli/build.js +2 -2
  50. package/local-cli/build.test.js +14 -14
  51. package/local-cli/cli.js +8 -6
  52. package/local-cli/init.js +61 -21
  53. package/local-cli/rebuild-framework-cache.js +1 -1
  54. package/local-cli/reset-lock-file.js +16 -0
  55. package/local-cli/templates/jest.js +13 -10
  56. package/local-cli/test.js +14 -8
  57. package/local-cli/test.test.js +148 -61
  58. package/local-cli/testCommand/TestRunnerCommand.js +78 -72
  59. package/local-cli/testCommand/builder.js +0 -1
  60. package/local-cli/testCommand/middlewares.js +4 -13
  61. package/local-cli/testCommand/warnings.js +0 -3
  62. package/local-cli/utils/jestInternals.js +4 -1
  63. package/package.json +23 -16
  64. package/runners/deprecation.js +42 -44
  65. package/runners/jest/globalSetup.js +1 -1
  66. package/runners/jest/globalTeardown.js +1 -1
  67. package/runners/jest/index.d.ts +60 -0
  68. package/runners/jest/index.js +3 -8
  69. package/runners/jest/index.test.js +13 -0
  70. package/runners/jest/reporters/DetoxReporter.js +33 -2
  71. package/runners/jest/testEnvironment/index.js +119 -69
  72. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +94 -51
  73. package/runners/jest/testEnvironment/listeners/DetoxPlatformFilterListener.js +1 -1
  74. package/runners/jest/testEnvironment/listeners/SpecReporter.js +14 -16
  75. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +2 -6
  76. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  77. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -1
  78. package/src/DetoxWorker.js +105 -62
  79. package/src/android/core/NativeElement.js +56 -20
  80. package/src/android/core/NativeExpect.js +28 -9
  81. package/src/android/interactions/native.js +25 -18
  82. package/src/artifacts/ArtifactsManager.js +14 -47
  83. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  84. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  85. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  86. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  87. package/src/artifacts/templates/plugin/ArtifactPlugin.js +1 -1
  88. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  89. package/src/artifacts/utils/temporaryPath.js +18 -7
  90. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  91. package/src/client/AsyncWebSocket.js +8 -17
  92. package/src/client/Client.js +19 -2
  93. package/src/client/actions/formatters/sync-resources/NetworkFormatter.js +1 -1
  94. package/src/configuration/collectCliConfig.js +1 -12
  95. package/src/configuration/composeAppsConfig.js +4 -0
  96. package/src/configuration/composeDeviceConfig.js +1 -1
  97. package/src/configuration/composeLoggerConfig.js +19 -10
  98. package/src/configuration/composeRunnerConfig.js +62 -9
  99. package/src/configuration/index.js +14 -9
  100. package/src/configuration/loadExternalConfig.js +1 -1
  101. package/src/devices/allocation/DeviceAllocator.js +3 -2
  102. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +5 -5
  103. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +4 -3
  104. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  105. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -2
  106. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  107. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +1 -1
  108. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  109. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  110. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  111. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  112. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  113. package/src/devices/common/drivers/android/tools/MonitoredInstrumentation.js +1 -1
  114. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +29 -3
  115. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +13 -15
  116. package/src/devices/runtime/RuntimeDevice.js +19 -12
  117. package/src/devices/runtime/drivers/DeviceDriverBase.js +1 -1
  118. package/src/devices/runtime/drivers/android/AndroidDriver.js +10 -2
  119. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +1 -1
  120. package/src/errors/DetoxConfigErrorComposer.js +17 -2
  121. package/src/ios/expectTwo.js +153 -67
  122. package/src/ipc/IPCClient.js +12 -12
  123. package/src/ipc/IPCServer.js +29 -18
  124. package/src/ipc/{state.js → SessionState.js} +26 -40
  125. package/src/logger/DetoxLogger.js +261 -157
  126. package/src/logger/index.js +5 -0
  127. package/src/logger/utils/BunyanLogger.js +76 -0
  128. package/src/logger/utils/CategoryThreadDispatcher.js +36 -0
  129. package/src/logger/utils/DetoxLogFinalizer.js +140 -0
  130. package/src/logger/utils/MessageStack.js +24 -0
  131. package/src/logger/utils/ThreadDispatcher.js +61 -0
  132. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +5 -4
  133. package/src/logger/utils/sanitizeBunyanContext.js +30 -0
  134. package/src/{utils → logger/utils}/streamUtils.js +51 -17
  135. package/src/logger/utils/tracerLegacy.js +37 -0
  136. package/src/realms/DetoxContext.js +78 -65
  137. package/src/realms/DetoxInternalsFacade.js +8 -12
  138. package/src/realms/DetoxPrimaryContext.js +104 -72
  139. package/src/realms/DetoxSecondaryContext.js +29 -32
  140. package/src/server/DetoxConnection.js +18 -23
  141. package/src/server/DetoxServer.js +7 -10
  142. package/src/server/DetoxSession.js +6 -6
  143. package/src/server/DetoxSessionManager.js +1 -1
  144. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  145. package/src/symbols.js +16 -22
  146. package/src/utils/Timer.js +55 -38
  147. package/src/utils/argparse.js +11 -0
  148. package/src/utils/childProcess/exec.js +1 -1
  149. package/src/utils/childProcess/spawn.js +1 -1
  150. package/src/utils/errorUtils.js +24 -3
  151. package/src/utils/invocationTraceDescriptions.js +43 -0
  152. package/src/utils/logger.js +1 -1
  153. package/src/utils/traceInvocationCall.js +21 -0
  154. package/src/utils/traceMethods.js +15 -0
  155. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  156. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  157. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  158. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  159. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  160. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  161. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  162. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  163. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.aar +0 -0
  164. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.aar.md5 +0 -1
  165. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.aar.sha1 +0 -1
  166. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.aar.sha256 +0 -1
  167. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.aar.sha512 +0 -1
  168. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  169. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  170. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  171. package/Detox-android/com/wix/detox/20.0.1-breaking.new-global-lifecycle.0/detox-20.0.1-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  172. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategy.kt +0 -84
  173. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +0 -115
  174. package/runners/jest/deprecation.js +0 -25
  175. package/src/configuration/utils/warnings.js +0 -12
  176. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  177. package/src/logger/DetoxTracer.js +0 -133
  178. package/src/logger/TraceThreadDispatcher.js +0 -52
  179. package/src/utils/ChromeTracingExporter.js +0 -54
  180. package/src/utils/trace.js +0 -19
package/local-cli/test.js CHANGED
@@ -3,24 +3,30 @@ const detox = require('../internals');
3
3
  const TestRunnerCommand = require('./testCommand/TestRunnerCommand');
4
4
 
5
5
  module.exports.command = 'test';
6
- module.exports.desc = 'Run your test suite with the test runner specified in package.json';
6
+ module.exports.desc = 'Run your test suites with the test runner specified in the project\'s Detox config';
7
7
  module.exports.builder = require('./testCommand/builder');
8
8
  module.exports.middlewares = require('./testCommand/middlewares').default;
9
9
 
10
10
  module.exports.handler = async function test({ detoxArgs, runnerArgs }) {
11
11
  try {
12
- await detox.globalSetup({
12
+ const opts = {
13
13
  argv: detoxArgs,
14
14
  testRunnerArgv: runnerArgs,
15
- });
15
+ workerId: null,
16
+ };
17
+
18
+ const config = await detox.resolveConfig(opts);
19
+ if (!config.cli.inspectBrk) {
20
+ await detox.init(opts);
21
+ }
16
22
 
17
- const runnerCommand = new TestRunnerCommand()
18
- .setRunnerConfig(detox.config.runnerConfig)
19
- .setDeviceConfig(detox.config.deviceConfig)
20
- .replicateCLIConfig(detox.config.cliConfig);
23
+ const runnerCommand = new TestRunnerCommand({
24
+ config,
25
+ env: process.env,
26
+ });
21
27
 
22
28
  await runnerCommand.execute();
23
29
  } finally {
24
- await detox.globalTeardown();
30
+ await detox.cleanup();
25
31
  }
26
32
  };
@@ -8,8 +8,11 @@ jest.mock('../src/devices/DeviceRegistry');
8
8
  jest.mock('../src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory');
9
9
  jest.mock('./utils/jestInternals');
10
10
 
11
+ const cp = require('child_process');
12
+ const cpSpawn = cp.spawn;
11
13
  const os = require('os');
12
14
  const path = require('path');
15
+ const util = require('util');
13
16
 
14
17
  const fs = require('fs-extra');
15
18
  const _ = require('lodash');
@@ -28,6 +31,10 @@ describe('CLI', () => {
28
31
  let GenyDeviceRegistryFactory;
29
32
  let jestInternals;
30
33
 
34
+ afterEach(() => {
35
+ cp.spawn = cpSpawn;
36
+ });
37
+
31
38
  beforeEach(() => {
32
39
  _cliCallDump = undefined;
33
40
  _env = process.env;
@@ -46,6 +53,7 @@ describe('CLI', () => {
46
53
  $0: os.platform() === 'win32' ? `node ${executable}` : executable,
47
54
  config: 'e2e/config.json'
48
55
  },
56
+ forwardEnv: true,
49
57
  },
50
58
  configurations: {
51
59
  single: {
@@ -100,23 +108,53 @@ describe('CLI', () => {
100
108
  ])('given no extra args (%s)', (_platform, deviceType) => {
101
109
  beforeEach(async () => {
102
110
  singleConfig().device.type = deviceType;
103
- await run();
104
111
  });
105
112
 
106
- test('should produce a default command', () => {
107
- expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
108
- });
113
+ describe('when testRunner.forwardEnv is true', () => {
114
+ beforeEach(async () => {
115
+ singleConfig().testRunner = { forwardEnv: true };
116
+ await run();
117
+ });
109
118
 
110
- test('should not override environment variables', () => {
111
- expect(cliCall().env).toEqual({ DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String) });
119
+ test('should produce a default command', () => {
120
+ expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
121
+ });
122
+
123
+ test('should override environment variables', () => {
124
+ expect(cliCall().env).toEqual({
125
+ DETOX_CONFIG_PATH: expect.any(String),
126
+ DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String)
127
+ });
128
+ });
129
+
130
+ test('should hint essential environment variables', () => {
131
+ expect(cliCall().fullCommand).toMatch(/\bDETOX_CONFIG_PATH=.*\bexecutable\b/);
132
+ });
112
133
  });
113
134
 
114
- test('should hint essential environment variables', () => {
115
- expect(cliCall().fullCommand).toMatch(/^DETOX_CONFIG_PATH=.*\bexecutable/);
135
+ describe('when testRunner.forwardEnv is false', () => {
136
+ beforeEach(async () => {
137
+ singleConfig().testRunner = { forwardEnv: false };
138
+ await run();
139
+ });
140
+
141
+ test('should produce a default command', () => {
142
+ expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
143
+ });
144
+
145
+ test('should not override environment variables', () => {
146
+ expect(cliCall().env).toEqual({
147
+ DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String)
148
+ });
149
+ });
150
+
151
+ test('should not hint essential environment variables', () => {
152
+ expect(cliCall().fullCommand).not.toMatch(/\bDETOX_CONFIG_PATH=.*\bexecutable\b/);
153
+ });
116
154
  });
117
155
  });
118
156
 
119
- test('should use runnerConfig.specs as default specs', async () => {
157
+ test('should use testRunner.args._ as default specs', async () => {
120
158
  detoxConfig.testRunner.args._ = ['e2e/sanity'];
121
159
  await run();
122
160
  expect(_.last(cliCall().argv)).toEqual('e2e/sanity');
@@ -129,7 +167,7 @@ describe('CLI', () => {
129
167
 
130
168
  test.each([['-l'], ['--loglevel']])('%s <value> should be passed as environment variable', async (__loglevel) => {
131
169
  await run(__loglevel, 'trace');
132
- expect(cliCall().env).not.toHaveProperty('DETOX_LOGLEVEL');
170
+ expect(cliCall().env).toHaveProperty('DETOX_LOGLEVEL');
133
171
  expect(cliCall().fullCommand).toMatch(/ DETOX_LOGLEVEL="trace" /);
134
172
  });
135
173
 
@@ -139,27 +177,67 @@ describe('CLI', () => {
139
177
  });
140
178
 
141
179
  test.each([['-R'], ['--retries']])('%s <value> should execute unsuccessful run N extra times', async (__retries) => {
180
+ function toTestResult(testFilePath) {
181
+ return {
182
+ testFilePath,
183
+ success: false,
184
+ isPermanentFailure: false,
185
+ };
186
+ }
187
+
142
188
  const context = require('../internals');
143
- context.session.failedTestFiles = ['e2e/failing1.test.js', 'e2e/failing2.test.js'];
144
- context.session.failedTestFiles.splice = jest.fn(() => {
145
- context.session.failedTestFiles = ['e2e/failing2.test.js'];
146
- });
189
+
190
+ jest.spyOn(cp, 'spawn')
191
+ .mockImplementationOnce((...args) => {
192
+ context.session.testResults = ['e2e/failing1.test.js', 'e2e/failing2.test.js'].map(toTestResult);
193
+ return cpSpawn(...args);
194
+ })
195
+ .mockImplementationOnce((...args) => {
196
+ context.session.testResults = ['e2e/failing2.test.js'].map(toTestResult);
197
+ return cpSpawn(...args);
198
+ })
199
+ .mockImplementationOnce((...args) => {
200
+ return cpSpawn(...args);
201
+ });
147
202
 
148
203
  mockExitCode(1);
149
204
 
150
205
  await run(__retries, 2).catch(_.noop);
151
206
 
152
- expect(cliCall(0).env).not.toHaveProperty('DETOX_RERUN_INDEX');
153
207
  expect(cliCall(0).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json']);
154
- expect(cliCall(0).fullCommand).not.toMatch(/DETOX_RERUN_INDEX/);
155
-
156
- expect(cliCall(1).env.DETOX_RERUN_INDEX).toBe('1');
157
208
  expect(cliCall(1).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json', 'e2e/failing1.test.js', 'e2e/failing2.test.js']);
158
- expect(cliCall(1).fullCommand).not.toMatch(/DETOX_RERUN_INDEX/);
159
-
160
209
  expect(cliCall(2).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json', 'e2e/failing2.test.js']);
161
- expect(cliCall(2).env.DETOX_RERUN_INDEX).toBe('2');
162
- expect(cliCall(2).fullCommand).not.toMatch(/DETOX_RERUN_INDEX/);
210
+ });
211
+
212
+ describe('when there are permanently failed tests', () => {
213
+ beforeEach(() => {
214
+ const context = require('../internals');
215
+ context.session.testResults = ['e2e/failing1.test.js', 'e2e/failing2.test.js'].map((testFilePath, index) => ({
216
+ testFilePath,
217
+ success: false,
218
+ isPermanentFailure: index > 0,
219
+ }));
220
+
221
+ mockExitCode(1);
222
+ });
223
+
224
+ test.each([['-R'], ['--retries']])('%s <value> should not bail by default', async (__retries) => {
225
+ await run(__retries, 2).catch(_.noop);
226
+
227
+ expect(cliCall(0).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json']);
228
+ expect(cliCall(1).env).not.toHaveProperty('DETOX_RERUN_INDEX');
229
+ expect(cliCall(1).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json', 'e2e/failing1.test.js']);
230
+ // note that it does not take the permanently failed test
231
+ });
232
+
233
+ test.each([['-R'], ['--retries']])('%s <value> should bail if configured', async (__retries) => {
234
+ detoxConfig.testRunner.bail = true;
235
+ await run(__retries, 2).catch(_.noop);
236
+
237
+ expect(cliCall(0).env).not.toHaveProperty('DETOX_RERUN_INDEX');
238
+ expect(cliCall(0).argv).toEqual([expect.stringMatching(/executable$/), '--config', 'e2e/config.json']);
239
+ expect(cliCall(1)).toBe(null);
240
+ });
163
241
  });
164
242
 
165
243
  test.each([['-R'], ['--retries']])('%s <value> should not restart test runner if there are no failing tests paths', async (__retries) => {
@@ -172,7 +250,11 @@ describe('CLI', () => {
172
250
 
173
251
  test.each([['-R'], ['--retries']])('%s <value> should retain -- <...explicitPassthroughArgs>', async (__retries) => {
174
252
  const context = require('../internals');
175
- context.session.failedTestFiles = ['tests/failing.test.js'];
253
+ context.session.testResults = [{
254
+ testFilePath: 'tests/failing.test.js',
255
+ success: false,
256
+ isPermanentFailure: false,
257
+ }];
176
258
 
177
259
  mockExitCode(1);
178
260
 
@@ -184,111 +266,104 @@ describe('CLI', () => {
184
266
 
185
267
  test.each([['-r'], ['--reuse']])('%s <value> should be passed as environment variable', async (__reuse) => {
186
268
  await run(__reuse);
187
- expect(cliCall().env).not.toHaveProperty('DETOX_REUSE');
269
+ expect(cliCall().env).toHaveProperty('DETOX_REUSE');
188
270
  expect(cliCall().fullCommand).toMatch(/\bDETOX_REUSE=true /);
189
271
  });
190
272
 
191
273
  test.each([['-u'], ['--cleanup']])('%s <value> should be passed as environment variable', async (__cleanup) => {
192
274
  await run(__cleanup);
193
- expect(cliCall().env).not.toHaveProperty('DETOX_CLEANUP');
275
+ expect(cliCall().env).toHaveProperty('DETOX_CLEANUP');
194
276
  expect(cliCall().fullCommand).toMatch(/\bDETOX_CLEANUP=true /);
195
277
  });
196
278
 
197
279
  test.each([['-d'], ['--debug-synchronization']])('%s <value> should be passed as environment variable', async (__debug_synchronization) => {
198
280
  await run(__debug_synchronization, 5000);
199
- expect(cliCall().env).not.toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
281
+ expect(cliCall().env).toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
200
282
  expect(cliCall().fullCommand).toMatch(/\bDETOX_DEBUG_SYNCHRONIZATION=5000 /);
201
283
  });
202
284
 
203
285
  test.each([['-d'], ['--debug-synchronization']])('%s <value> should be passed as 0 when given false', async (__debug_synchronization) => {
204
286
  await run(__debug_synchronization, false);
205
- expect(cliCall().env).not.toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
287
+ expect(cliCall().env).toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
206
288
  expect(cliCall().fullCommand).toMatch(/\bDETOX_DEBUG_SYNCHRONIZATION=0 /);
207
289
  });
208
290
 
209
291
  test.each([['-d'], ['--debug-synchronization']])('%s <value> should have default value = 3000', async (__debug_synchronization) => {
210
292
  await run(`${__debug_synchronization}`);
211
- expect(cliCall().env).not.toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
293
+ expect(cliCall().env).toHaveProperty('DETOX_DEBUG_SYNCHRONIZATION');
212
294
  expect(cliCall().fullCommand).toMatch(/\bDETOX_DEBUG_SYNCHRONIZATION=3000 /);
213
295
  });
214
296
 
215
297
  test.each([['-a'], ['--artifacts-location']])('%s <value> should be passed as environment variable', async (__artifacts_location) => {
216
298
  await run(__artifacts_location, '/tmp');
217
- expect(cliCall().env).not.toHaveProperty('DETOX_ARTIFACTS_LOCATION');
299
+ expect(cliCall().env).toHaveProperty('DETOX_ARTIFACTS_LOCATION');
218
300
  expect(cliCall().fullCommand).toMatch(/\bDETOX_ARTIFACTS_LOCATION="\/tmp" /);
219
301
  });
220
302
 
221
303
  test('--record-logs <value> should be passed as environment variable', async () => {
222
304
  await run('--record-logs', 'all');
223
- expect(cliCall().env).not.toHaveProperty('DETOX_RECORD_LOGS');
305
+ expect(cliCall().env).toHaveProperty('DETOX_RECORD_LOGS');
224
306
  expect(cliCall().fullCommand).toMatch(/\bDETOX_RECORD_LOGS="all" /);
225
307
  });
226
308
 
227
309
  test('--take-screenshots <value> should be passed as environment variable', async () => {
228
310
  await run('--take-screenshots', 'failing');
229
- expect(cliCall().env).not.toHaveProperty('DETOX_TAKE_SCREENSHOTS');
311
+ expect(cliCall().env).toHaveProperty('DETOX_TAKE_SCREENSHOTS');
230
312
  expect(cliCall().fullCommand).toMatch(/\bDETOX_TAKE_SCREENSHOTS="failing" /);
231
313
  });
232
314
 
233
315
  test('--record-videos <value> should be passed as environment variable', async () => {
234
316
  await run('--record-videos', 'failing');
235
- expect(cliCall().env).not.toHaveProperty('DETOX_RECORD_VIDEOS');
317
+ expect(cliCall().env).toHaveProperty('DETOX_RECORD_VIDEOS');
236
318
  expect(cliCall().fullCommand).toMatch(/\bDETOX_RECORD_VIDEOS="failing" /);
237
319
  });
238
320
 
239
321
  test('--record-performance <value> should be passed as environment variable', async () => {
240
322
  await run('--record-performance', 'all');
241
- expect(cliCall().env).not.toHaveProperty('DETOX_RECORD_PERFORMANCE');
323
+ expect(cliCall().env).toHaveProperty('DETOX_RECORD_PERFORMANCE');
242
324
  expect(cliCall().fullCommand).toMatch(/\DETOX_RECORD_PERFORMANCE="all" /);
243
325
  });
244
326
 
245
327
  test('--capture-view-hierarchy <value> should be passed as environment variable', async () => {
246
328
  await run('--capture-view-hierarchy', 'enabled');
247
- expect(cliCall().env).not.toHaveProperty('DETOX_CAPTURE_VIEW_HIERARCHY');
329
+ expect(cliCall().env).toHaveProperty('DETOX_CAPTURE_VIEW_HIERARCHY');
248
330
  expect(cliCall().fullCommand).toMatch(/\DETOX_CAPTURE_VIEW_HIERARCHY="enabled" /);
249
331
  });
250
332
 
251
333
  test('--jest-report-specs, set explicitly, should be passed as an environment variable', async () => {
252
334
  await run('--jest-report-specs');
253
- expect(cliCall().env).not.toHaveProperty('DETOX_REPORT_SPECS');
335
+ expect(cliCall().env).toHaveProperty('DETOX_REPORT_SPECS');
254
336
  expect(cliCall().fullCommand).toMatch(/\bDETOX_REPORT_SPECS=true /);
255
337
  });
256
338
 
257
339
  test.each([['-H'], ['--headless']])('%s <value> should be passed as environment variable', async (__headless) => {
258
340
  await run(__headless);
259
- expect(cliCall().env).not.toHaveProperty('DETOX_HEADLESS');
341
+ expect(cliCall().env).toHaveProperty('DETOX_HEADLESS');
260
342
  expect(cliCall().fullCommand).toMatch(/\bDETOX_HEADLESS=true /);
261
343
  });
262
344
 
263
345
  test('--gpu <value> should be passed as environment variable', async () => {
264
346
  await run('--gpu', 'angle_indirect');
265
- expect(cliCall().env).not.toHaveProperty('DETOX_GPU');
347
+ expect(cliCall().env).toHaveProperty('DETOX_GPU');
266
348
  expect(cliCall().fullCommand).toMatch(/\bDETOX_GPU="angle_indirect" /);
267
349
  });
268
350
 
269
351
  test('--device-boot-args should be passed as an environment variable (without deprecation warnings)', async () => {
270
352
  await run('--device-boot-args="--verbose"');
271
- expect(cliCall().env).not.toHaveProperty('DETOX_DEVICE_BOOT_ARGS');
353
+ expect(cliCall().env).toHaveProperty('DETOX_DEVICE_BOOT_ARGS');
272
354
  expect(cliCall().fullCommand).toMatch(/\bDETOX_DEVICE_BOOT_ARGS="--verbose" /);
273
355
  expect(logger().warn).not.toHaveBeenCalledWith(DEVICE_LAUNCH_ARGS_DEPRECATION);
274
356
  });
275
357
 
276
- test('--device-launch-args should serve as a deprecated alias to --device-boot-args', async () => {
277
- await run(`--device-launch-args="--verbose"`);
278
- expect(cliCall().env).not.toHaveProperty('DETOX_DEVICE_BOOT_ARGS');
279
- expect(cliCall().fullCommand).toMatch(/\bDETOX_DEVICE_BOOT_ARGS="--verbose" /);
280
- expect(logger().warn).toHaveBeenCalledWith(DEVICE_LAUNCH_ARGS_DEPRECATION);
281
- });
282
-
283
358
  test('--app-launch-args should be passed as an environment variable', async () => {
284
359
  await run(`--app-launch-args="--debug yes"`);
285
- expect(cliCall().env).not.toHaveProperty('DETOX_APP_LAUNCH_ARGS');
360
+ expect(cliCall().env).toHaveProperty('DETOX_APP_LAUNCH_ARGS');
286
361
  expect(cliCall().fullCommand).toMatch(/\bDETOX_APP_LAUNCH_ARGS="--debug yes" /);
287
362
  });
288
363
 
289
364
  test('--use-custom-logger false should be prevent passing environment variable', async () => {
290
365
  await run(`--use-custom-logger=false`);
291
- expect(cliCall().env).not.toHaveProperty('DETOX_USE_CUSTOM_LOGGER');
366
+ expect(cliCall().env).toHaveProperty('DETOX_USE_CUSTOM_LOGGER');
292
367
  expect(cliCall().fullCommand).toMatch(/\bDETOX_USE_CUSTOM_LOGGER=false /);
293
368
  });
294
369
 
@@ -302,13 +377,13 @@ describe('CLI', () => {
302
377
  test('--force-adb-install should be passed as environment variable', async () => {
303
378
  singleConfig().device.type = 'android.emulator';
304
379
  await run(`--force-adb-install`);
305
- expect(cliCall().env).not.toHaveProperty('DETOX_FORCE_ADB_INSTALL');
380
+ expect(cliCall().env).toHaveProperty('DETOX_FORCE_ADB_INSTALL');
306
381
  expect(cliCall().fullCommand).toMatch(/\bDETOX_FORCE_ADB_INSTALL=true /);
307
382
  });
308
383
 
309
384
  test.each([['-n'], ['--device-name']])('%s <value> should be passed as environment variable', async (__device_name) => {
310
385
  await run(__device_name, 'TheDevice');
311
- expect(cliCall().env).not.toHaveProperty('DETOX_DEVICE_NAME');
386
+ expect(cliCall().env).toHaveProperty('DETOX_DEVICE_NAME');
312
387
  expect(cliCall().fullCommand).toMatch(/\bDETOX_DEVICE_NAME="TheDevice" /);
313
388
  });
314
389
 
@@ -320,8 +395,6 @@ describe('CLI', () => {
320
395
  expect(cliCall().argv.slice(-2)).toEqual(['e2e/01.sanity.test.js', 'e2e/02.sanity.test.js']);
321
396
  });
322
397
 
323
- test.todo('--inspect-brk should work');
324
-
325
398
  test.each([
326
399
  ['-d e2eFolder', / e2eFolder$/, /\bDETOX_DEBUG_SYNCHRONIZATION=3000/],
327
400
  ['--debug-synchronization e2eFolder', / e2eFolder$/, /\bDETOX_DEBUG_SYNCHRONIZATION=3000/],
@@ -399,15 +472,14 @@ describe('CLI', () => {
399
472
  expect(cliCall().argv).toContain('--deepParameter');
400
473
  });
401
474
 
402
- // TODO: revive this test
403
- test.skip('--inspect-brk should prepend "node --inspect-brk" to the command', async () => {
404
- await run('--inspect-brk');
475
+ test('--inspect-brk should activate inspectBrk hook', async () => {
476
+ detoxConfig.testRunner.inspectBrk = (config) => {
477
+ config.args.customFlag = true;
478
+ return config;
479
+ };
405
480
 
406
- if (process.platform === 'win32') {
407
- expect(cliCall().argv).toMatch(/^node --inspect-brk \.\/node_modules\/jest\/bin\/jest\.js/);
408
- } else {
409
- expect(cliCall().argv).toMatch(/^node --inspect-brk \.\/node_modules\/\.bin\/jest/);
410
- }
481
+ await run('--inspect-brk');
482
+ expect(cliCall().argv).toContain('--customFlag');
411
483
  });
412
484
 
413
485
  test('should append $DETOX_ARGV_OVERRIDE to detox test ... command and print a warning', async () => {
@@ -423,6 +495,16 @@ describe('CLI', () => {
423
495
  expect(logger().warn).toHaveBeenCalledWith(expect.stringContaining('$DETOX_ARGV_OVERRIDE is detected'));
424
496
  });
425
497
 
498
+ test('should append $DETOX_ARGV_OVERRIDE "--" part to test runner command', async () => {
499
+ process.env.PLATFORM = 'ios';
500
+ process.env.DETOX_ARGV_OVERRIDE = '-- --help';
501
+
502
+ await run();
503
+
504
+ expect(cliCall().argv.slice(-1)).toEqual(['--help']);
505
+ expect(logger().warn).toHaveBeenCalledWith(expect.stringContaining('$DETOX_ARGV_OVERRIDE is detected'));
506
+ });
507
+
426
508
  // Helpers
427
509
 
428
510
  function tempfile(extension, content) {
@@ -477,7 +559,12 @@ describe('CLI', () => {
477
559
  }
478
560
 
479
561
  async function run(...args) {
480
- detoxConfigPath = tempfile('.json', JSON.stringify(detoxConfig));
562
+ let contents = `module.exports = ${util.inspect(detoxConfig, { depth: Infinity })};`;
563
+ if (detoxConfig.testRunner && detoxConfig.testRunner.inspectBrk) {
564
+ contents = contents.replace(/\[Function.*\]/m, detoxConfig.testRunner.inspectBrk.toString());
565
+ }
566
+
567
+ detoxConfigPath = tempfile('.js', contents);
481
568
  const __configPath = Math.random() > 0.5 ? '-C' : '--config-path';
482
569
  return runRaw('test', __configPath, detoxConfigPath, ...args);
483
570
  }
@@ -498,7 +585,7 @@ describe('CLI', () => {
498
585
  return {
499
586
  ...mockCall,
500
587
  fullCommand: _.chain(logger().log.mock.calls)
501
- .filter(([_level, _childMeta, meta]) => meta && meta.event === 'RUN_START')
588
+ .filter(([_level, _childMeta, meta]) => meta && meta.env)
502
589
  .get(index)
503
590
  .get(3)
504
591
  .value(),
@@ -5,51 +5,83 @@ const parser = require('yargs-parser');
5
5
  const unparse = require('yargs-unparser');
6
6
 
7
7
  const detox = require('../../internals');
8
+ const log = detox.log.child({ cat: ['lifecycle', 'cli'] });
8
9
  const { DetoxRuntimeError } = require('../../src/errors');
9
10
  const { printEnvironmentVariables, prependNodeModulesBinToPATH } = require('../../src/utils/envUtils');
10
11
  const { escapeSpaces } = require('../../src/utils/shellUtils');
11
12
 
12
13
  class TestRunnerCommand {
13
- constructor() {
14
- this._argv = {};
15
- this._env = {};
16
- this._envHint = {};
17
- this._retries = 0;
18
- /** @type {Detox.DetoxDeviceConfig} */
19
- this._deviceConfig = null;
14
+ /*
15
+ @param {object} opts
16
+ @param {DetoxInternals.RuntimeConfig} opts.config
17
+ @param {ProcessEnv} opts.env
18
+ */
19
+ constructor(opts) {
20
+ const cliConfig = opts.config.cli;
21
+ const deviceConfig = opts.config.device;
22
+ const runnerConfig = opts.config.testRunner;
23
+
24
+ this._argv = runnerConfig.args;
25
+ this._retries = runnerConfig.retries;
26
+ this._envHint = this._buildEnvHint(opts.env);
27
+ this._envFwd = {};
28
+ if (runnerConfig.forwardEnv) {
29
+ this._envFwd = this._buildEnvOverride(cliConfig, deviceConfig);
30
+ Object.assign(this._envHint, this._envFwd);
31
+ }
20
32
  }
21
33
 
22
- /**
23
- * @param {Detox.DetoxDeviceConfig} config
24
- * @returns {this}
25
- */
26
- setDeviceConfig(config) {
27
- this._deviceConfig = config;
34
+ async execute() {
35
+ let runsLeft = 1 + this._retries;
36
+ let launchError = null;
28
37
 
29
- return this;
30
- }
38
+ do {
39
+ try {
40
+ await this._spawnTestRunner();
41
+ launchError = null;
42
+ } catch (e) {
43
+ launchError = e;
31
44
 
32
- /**
33
- * @param {Detox.DetoxTestRunnerConfig} config
34
- * @returns {this}
35
- */
36
- setRunnerConfig(config) {
37
- this._argv = config.args;
38
- this._retries = config.retries;
45
+ const failedTestFiles = detox.session.testResults.filter(r => !r.success);
39
46
 
40
- if (config.inspectBrk === true) {
41
- this._env = this._envHint;
47
+ const { bail } = detox.config.testRunner;
48
+ if (bail && failedTestFiles.some(r => r.isPermanentFailure)) {
49
+ throw e;
50
+ }
51
+
52
+ const testFilesToRetry = failedTestFiles.filter(r => !r.isPermanentFailure).map(r => r.testFilePath);
53
+ if (_.isEmpty(testFilesToRetry)) {
54
+ throw e;
55
+ }
56
+
57
+ if (--runsLeft > 0) {
58
+ // @ts-ignore
59
+ detox.session.testSessionIndex++; // it is always the primary context, so we can update it
60
+ this._argv._ = testFilesToRetry;
61
+ this._logRelaunchError();
62
+ }
63
+ }
64
+ } while (launchError && runsLeft > 0);
65
+
66
+ if (launchError) {
67
+ throw launchError;
42
68
  }
69
+ }
43
70
 
44
- return this;
71
+ _buildEnvHint(env) {
72
+ return _(env)
73
+ .mapKeys((_value, key) => key.toUpperCase())
74
+ .pickBy((_value, key) => key.startsWith('DETOX_'))
75
+ .omit(['DETOX_CONFIG_SNAPSHOT_PATH'])
76
+ .value();
45
77
  }
46
78
 
47
79
  /**
48
- * @param {Partial<Readonly<DetoxInternals.DetoxCLIConfig>>} cliConfig
49
- * @returns {this}
80
+ * @param {DetoxInternals.CLIConfig} cliConfig
81
+ * @param {Detox.DetoxDeviceConfig} deviceConfig
50
82
  */
51
- replicateCLIConfig(cliConfig) {
52
- this._envHint = _.omitBy({
83
+ _buildEnvOverride(cliConfig, deviceConfig) {
84
+ return _.omitBy({
53
85
  DETOX_APP_LAUNCH_ARGS: cliConfig.appLaunchArgs,
54
86
  DETOX_ARTIFACTS_LOCATION: cliConfig.artifactsLocation,
55
87
  DETOX_CAPTURE_VIEW_HIERARCHY: cliConfig.captureViewHierarchy,
@@ -59,7 +91,7 @@ class TestRunnerCommand {
59
91
  DETOX_DEBUG_SYNCHRONIZATION: cliConfig.debugSynchronization,
60
92
  DETOX_DEVICE_BOOT_ARGS: cliConfig.deviceBootArgs,
61
93
  DETOX_DEVICE_NAME: cliConfig.deviceName,
62
- DETOX_FORCE_ADB_INSTALL: this._deviceConfig.type.startsWith('android.')
94
+ DETOX_FORCE_ADB_INSTALL: deviceConfig.type.startsWith('android.')
63
95
  ? cliConfig.forceAdbInstall
64
96
  : undefined,
65
97
  DETOX_GPU: cliConfig.gpu,
@@ -76,51 +108,13 @@ class TestRunnerCommand {
76
108
  DETOX_TAKE_SCREENSHOTS: cliConfig.takeScreenshots,
77
109
  DETOX_USE_CUSTOM_LOGGER: cliConfig.useCustomLogger,
78
110
  }, _.isUndefined);
79
-
80
- return this;
81
111
  }
82
112
 
83
- async execute() {
84
- let runsLeft = 1 + this._retries;
85
- let launchError;
86
-
87
- do {
88
- try {
89
- if (launchError) {
90
- const list = this._argv._.map((file, index) => ` ${index + 1}. ${file}`).join('\n');
91
- detox.log.error(
92
- `There were failing tests in the following files:\n${list}\n\n` +
93
- 'Detox CLI is going to restart the test runner with those files...\n'
94
- );
95
- }
96
-
97
- await this._doExecute();
98
- launchError = null;
99
- } catch (e) {
100
- launchError = e;
101
-
102
- // @ts-ignore
103
- const { failedTestFiles } = detox.session;
104
- if (_.isEmpty(failedTestFiles)) {
105
- throw e;
106
- }
107
-
108
- this._argv._ = failedTestFiles.slice();
109
- this._env.DETOX_RERUN_INDEX = 1 + (this._env.DETOX_RERUN_INDEX || 0);
110
- failedTestFiles.splice(0, Infinity);
111
- }
112
- } while (launchError && --runsLeft > 0);
113
-
114
- if (launchError) {
115
- throw launchError;
116
- }
117
- }
118
-
119
- async _doExecute() {
113
+ async _spawnTestRunner() {
120
114
  const fullCommand = this._buildSpawnArguments().map(escapeSpaces);
121
115
  const fullCommandWithHint = printEnvironmentVariables(this._envHint) + fullCommand.join(' ');
122
116
 
123
- detox.log.info({ event: 'RUN_START', env: this._envHint }, fullCommandWithHint);
117
+ log.info({ env: this._envHint }, fullCommandWithHint);
124
118
 
125
119
  return new Promise((resolve, reject) => {
126
120
  cp.spawn(fullCommand[0], fullCommand.slice(1), {
@@ -128,12 +122,12 @@ class TestRunnerCommand {
128
122
  stdio: 'inherit',
129
123
  env: _({})
130
124
  .assign(process.env)
131
- .assign(this._env)
125
+ .assign(this._envFwd)
132
126
  .omitBy(_.isUndefined)
133
127
  .tap(prependNodeModulesBinToPATH)
134
128
  .value()
135
129
  })
136
- .on('error', (err) => reject(err))
130
+ .on('error', /* istanbul ignore next */ (err) => reject(err))
137
131
  .on('exit', (code) => code === 0
138
132
  ? resolve()
139
133
  : reject(new DetoxRuntimeError(`Command failed with exit code = ${code}:\n${fullCommandWithHint}`)
@@ -142,6 +136,7 @@ class TestRunnerCommand {
142
136
  }
143
137
 
144
138
  _buildSpawnArguments() {
139
+ /* istanbul ignore next */
145
140
  const { _: specs = [], '--': passthrough = [], $0, ...argv } = this._argv;
146
141
  const { _: $0_, ...$0argv } = parser($0);
147
142
 
@@ -152,6 +147,17 @@ class TestRunnerCommand {
152
147
  ...unparse({ _: [...passthrough, ...specs] }),
153
148
  ].map(String);
154
149
  }
150
+
151
+ _logRelaunchError() {
152
+ const list = this._argv._.map((file, index) => {
153
+ return ` ${index + 1}. ${file}`;
154
+ }).join('\n');
155
+
156
+ log.error(
157
+ `There were failing tests in the following files:\n${list}\n\n` +
158
+ 'Detox CLI is going to restart the test runner with those files...\n'
159
+ );
160
+ }
155
161
  }
156
162
 
157
163
  module.exports = TestRunnerCommand;
@@ -109,7 +109,6 @@ module.exports = {
109
109
  describe: 'Override the device name specified in a configuration. Useful for running a single build configuration on multiple devices.',
110
110
  },
111
111
  'device-boot-args': {
112
- alias: 'device-launch-args',
113
112
  group: 'Execution:',
114
113
  describe: 'Custom arguments to pass (through) onto the device (emulator/simulator) binary when booted.',
115
114
  },