detox 21.0.0-rc.6 → 21.0.0-rc.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. package/.eslintignore +1 -0
  2. package/Detox-android/com/wix/detox/{21.0.0-rc.6/detox-21.0.0-rc.6-javadoc.jar → 21.0.0-rc.7/detox-21.0.0-rc.7-javadoc.jar} +0 -0
  3. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-javadoc.jar.md5 +1 -0
  4. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-javadoc.jar.sha1 +1 -0
  5. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-javadoc.jar.sha256 +1 -0
  6. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-javadoc.jar.sha512 +1 -0
  7. package/Detox-android/com/wix/detox/{21.0.0-rc.6/detox-21.0.0-rc.6-sources.jar → 21.0.0-rc.7/detox-21.0.0-rc.7-sources.jar} +0 -0
  8. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-sources.jar.md5 +1 -0
  9. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-sources.jar.sha1 +1 -0
  10. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-sources.jar.sha256 +1 -0
  11. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7-sources.jar.sha512 +1 -0
  12. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.aar +0 -0
  13. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.aar.md5 +1 -0
  14. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.aar.sha1 +1 -0
  15. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.aar.sha256 +1 -0
  16. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.aar.sha512 +1 -0
  17. package/Detox-android/com/wix/detox/{21.0.0-rc.6/detox-21.0.0-rc.6.pom → 21.0.0-rc.7/detox-21.0.0-rc.7.pom} +1 -7
  18. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.pom.md5 +1 -0
  19. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.pom.sha1 +1 -0
  20. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.pom.sha256 +1 -0
  21. package/Detox-android/com/wix/detox/21.0.0-rc.7/detox-21.0.0-rc.7.pom.sha512 +1 -0
  22. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  26. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  27. package/Detox-ios-framework.tbz +0 -0
  28. package/Detox-ios-src.tbz +0 -0
  29. package/Detox-ios-xcuitest.tbz +0 -0
  30. package/android/detox/build.gradle +13 -8
  31. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAssertion.java +44 -25
  32. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +6 -7
  33. package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +2 -2
  34. package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +34 -35
  35. package/android/detox/src/full/java/com/wix/detox/espresso/common/MaterialSliderHelper.kt +21 -0
  36. package/android/detox/src/full/java/com/wix/detox/espresso/common/{SliderHelper.kt → ReactSliderHelper.kt} +6 -5
  37. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewMatchers.kt +2 -2
  38. package/android/detox/src/full/java/com/wix/detox/espresso/performer/MultipleViewsActionPerformer.kt +43 -0
  39. package/android/detox/src/full/java/com/wix/detox/espresso/performer/SingleViewActionPerformer.kt +19 -0
  40. package/android/detox/src/full/java/com/wix/detox/espresso/performer/ViewActionPerformer.kt +24 -0
  41. package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +4 -4
  42. package/android/detox/src/full/java/com/wix/invoke/types/Invocation.java +7 -6
  43. package/android/detox/src/main/java/com/wix/detox/espresso/MultipleViewsAction.kt +4 -0
  44. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -1
  45. package/android/detox/src/main/java/com/wix/detox/espresso/ViewActionWithResult.kt +2 -1
  46. package/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt +60 -4
  47. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +6 -5
  48. package/android/detox/src/testFull/java/com/wix/detox/espresso/common/MaterialSliderHelperTest.kt +33 -0
  49. package/android/detox/src/testFull/java/com/wix/detox/espresso/common/{SliderHelperTest.kt → ReactSliderHelperTest.kt} +3 -3
  50. package/android/detox/src/testFull/java/com/wix/detox/espresso/performer/ViewActionPerformerSpec.kt +37 -0
  51. package/android/detox/src/testFull/java/com/wix/invoke/JsonParserTest.java +23 -7
  52. package/android/detox/src/testFull/resources/targetInvocationEspressoWebDetoxScript.json +47 -0
  53. package/detox.d.ts +1830 -0
  54. package/globals.d.ts +23 -0
  55. package/index.d.ts +2 -1823
  56. package/internals.d.ts +11 -1
  57. package/jest.config.js +108 -0
  58. package/local-cli/reset-lock-file.js +5 -9
  59. package/local-cli/testCommand/TestRunnerCommand.js +26 -3
  60. package/local-cli/utils/interruptListeners.js +15 -0
  61. package/package.json +2 -100
  62. package/runners/jest/reporter.js +21 -1
  63. package/runners/jest/reporters/DetoxIPCReporter.js +34 -0
  64. package/runners/jest/reporters/DetoxReporterDispatcher.js +144 -0
  65. package/runners/jest/reporters/DetoxSummaryReporter.js +16 -0
  66. package/runners/jest/reporters/DetoxVerboseReporter.js +16 -0
  67. package/runners/jest/reporters/index.js +6 -0
  68. package/runners/jest/testEnvironment/index.js +11 -0
  69. package/src/DetoxWorker.js +5 -11
  70. package/src/android/core/NativeElement.js +26 -29
  71. package/src/android/core/WebElement.js +24 -6
  72. package/src/android/espressoapi/DetoxAssertion.js +16 -14
  73. package/src/android/espressoapi/EspressoDetox.js +9 -2
  74. package/src/android/espressoapi/web/WebElement.js +1 -4
  75. package/src/android/interactions/native.js +2 -3
  76. package/src/artifacts/providers/index.js +3 -3
  77. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +0 -17
  78. package/src/configuration/composeLoggerConfig.js +1 -0
  79. package/src/configuration/composeRunnerConfig.js +3 -1
  80. package/src/devices/allocation/DeviceAllocator.js +66 -20
  81. package/src/devices/allocation/DeviceList.js +44 -0
  82. package/src/devices/allocation/DeviceRegistry.js +189 -0
  83. package/src/devices/allocation/drivers/AllocationDriverBase.d.ts +15 -0
  84. package/src/devices/{common/drivers/android/tools → allocation/drivers/android}/FreeDeviceFinder.js +11 -10
  85. package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +22 -17
  86. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +97 -38
  87. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +32 -45
  88. package/src/devices/allocation/drivers/android/emulator/FreeEmulatorFinder.js +1 -1
  89. package/src/devices/allocation/drivers/android/emulator/FreePortFinder.js +37 -0
  90. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -3
  91. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +104 -32
  92. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceLauncher.js +40 -31
  93. package/src/devices/allocation/drivers/android/genycloud/GenyRegistry.js +121 -0
  94. package/src/devices/allocation/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +24 -0
  95. package/src/devices/{common → allocation}/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  96. package/src/devices/allocation/drivers/android/genycloud/services/dto/GenyInstance.js +83 -0
  97. package/src/devices/allocation/drivers/android/genycloud/services/dto/GenyRecipe.js +25 -0
  98. package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +95 -54
  99. package/src/devices/allocation/drivers/ios/SimulatorQuery.js +24 -0
  100. package/src/devices/allocation/factories/android.js +29 -35
  101. package/src/devices/allocation/factories/ios.js +6 -7
  102. package/src/devices/common/drivers/DeviceCookie.d.ts +12 -0
  103. package/src/devices/common/drivers/android/cookies.d.ts +11 -0
  104. package/src/devices/common/drivers/android/emulator/exec/EmulatorExec.js +17 -5
  105. package/src/devices/common/drivers/android/exec/ADB.js +1 -0
  106. package/src/devices/common/drivers/android/tools/instrumentationArgs.js +7 -1
  107. package/src/devices/common/drivers/ios/cookies.d.ts +9 -0
  108. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +3 -1
  109. package/src/devices/cookies/index.js +0 -6
  110. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +7 -6
  111. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +5 -4
  112. package/src/devices/runtime/factories/android.js +3 -11
  113. package/src/devices/runtime/factories/ios.js +3 -4
  114. package/src/{servicelocator → devices/servicelocator}/android/emulatorServiceLocator.js +1 -1
  115. package/src/devices/servicelocator/android/genycloudServiceLocator.js +17 -0
  116. package/src/devices/servicelocator/android/index.js +23 -0
  117. package/src/{validation → devices/validation}/EnvironmentValidatorBase.js +1 -0
  118. package/src/{validation → devices/validation}/android/GenycloudEnvValidator.js +2 -2
  119. package/src/{validation → devices/validation}/factories/index.js +1 -1
  120. package/src/{validation → devices/validation}/ios/IosSimulatorEnvValidator.js +2 -2
  121. package/src/environmentFactory.js +1 -11
  122. package/src/ios/web.js +21 -5
  123. package/src/ipc/IPCClient.js +22 -1
  124. package/src/ipc/IPCServer.js +42 -1
  125. package/src/ipc/SessionState.js +1 -0
  126. package/src/logger/DetoxLogger.js +2 -2
  127. package/src/realms/DetoxContext.js +8 -0
  128. package/src/realms/DetoxInternalsFacade.js +1 -0
  129. package/src/realms/DetoxPrimaryContext.js +48 -42
  130. package/src/realms/DetoxSecondaryContext.js +27 -0
  131. package/src/realms/symbols.js +6 -0
  132. package/src/utils/PIDService.js +27 -0
  133. package/src/utils/assertIsFunction.js +35 -0
  134. package/src/utils/environment.js +8 -15
  135. package/src/utils/errorUtils.js +3 -3
  136. package/src/utils/isArrowFunction.js +24 -0
  137. package/tsconfig.json +8 -3
  138. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-javadoc.jar.md5 +0 -1
  139. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-javadoc.jar.sha1 +0 -1
  140. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-javadoc.jar.sha256 +0 -1
  141. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-javadoc.jar.sha512 +0 -1
  142. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-sources.jar.md5 +0 -1
  143. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-sources.jar.sha1 +0 -1
  144. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-sources.jar.sha256 +0 -1
  145. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6-sources.jar.sha512 +0 -1
  146. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.aar +0 -0
  147. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.aar.md5 +0 -1
  148. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.aar.sha1 +0 -1
  149. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.aar.sha256 +0 -1
  150. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.aar.sha512 +0 -1
  151. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.pom.md5 +0 -1
  152. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.pom.sha1 +0 -1
  153. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.pom.sha256 +0 -1
  154. package/Detox-android/com/wix/detox/21.0.0-rc.6/detox-21.0.0-rc.6.pom.sha512 +0 -1
  155. package/runners/jest/reporters/DetoxReporter.js +0 -36
  156. package/src/devices/DeviceRegistry.js +0 -176
  157. package/src/devices/allocation/drivers/AllocationDriverBase.js +0 -30
  158. package/src/devices/allocation/drivers/android/attached/AttachedAndroidLauncher.js +0 -13
  159. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +0 -72
  160. package/src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory.js +0 -16
  161. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +0 -65
  162. package/src/devices/allocation/drivers/ios/SimulatorLauncher.js +0 -21
  163. package/src/devices/common/drivers/DeviceAllocationHelper.js +0 -20
  164. package/src/devices/common/drivers/DeviceLauncher.js +0 -19
  165. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +0 -25
  166. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLookupService.js +0 -38
  167. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +0 -14
  168. package/src/devices/common/drivers/android/genycloud/services/dto/GenyInstance.js +0 -66
  169. package/src/devices/common/drivers/android/genycloud/services/dto/GenyRecipe.js +0 -13
  170. package/src/devices/cookies/AndroidDeviceCookie.js +0 -13
  171. package/src/devices/cookies/AndroidEmulatorCookie.js +0 -6
  172. package/src/devices/cookies/AttachedAndroidDeviceCookie.js +0 -12
  173. package/src/devices/cookies/DeviceCookie.js +0 -4
  174. package/src/devices/cookies/GenycloudEmulatorCookie.js +0 -20
  175. package/src/devices/cookies/IosCookie.js +0 -6
  176. package/src/devices/cookies/IosSimulatorCookie.js +0 -10
  177. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +0 -71
  178. package/src/devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory.js +0 -18
  179. package/src/servicelocator/android/genycloudServiceLocator.js +0 -21
  180. package/src/servicelocator/android/index.js +0 -25
  181. package/src/servicelocator/ios.js +0 -7
  182. /package/src/devices/{common → allocation}/drivers/android/genycloud/exec/GenyCloudExec.js +0 -0
  183. /package/src/devices/{common → allocation}/drivers/android/genycloud/services/GenyAuthService.js +0 -0
package/internals.d.ts CHANGED
@@ -113,7 +113,12 @@ declare global {
113
113
  /** Test suite name */
114
114
  name: string;
115
115
  }): Promise<void>;
116
-
116
+ /**
117
+ * Workaround for Jest exiting abruptly in --bail mode.
118
+ * Makes sure that all workers and their test environments are properly torn down.
119
+ * @param [permanent] - forbids further retries
120
+ */
121
+ unsafe_conductEarlyTeardown(permanent?: boolean): Promise<void>;
117
122
  /**
118
123
  * Reports to Detox CLI about passed and failed test files.
119
124
  * The failed test files might be re-run again if
@@ -215,6 +220,11 @@ declare global {
215
220
  * Randomly generated ID for the entire Detox test session, including retries.
216
221
  */
217
222
  id: string;
223
+ /**
224
+ * Signalizes that the test session is being torn down.
225
+ * Experimental feature for Jest --bail mode.
226
+ */
227
+ unsafe_earlyTeardown?: boolean;
218
228
  /**
219
229
  * Results of test file executions. Primarily used for Detox CLI retry mechanism.
220
230
  */
package/jest.config.js ADDED
@@ -0,0 +1,108 @@
1
+ const DEBUG = process.argv.includes('--reporters');
2
+
3
+ /** @type{import('jest-allure2-reporter').ReporterOptions} */
4
+ const jestAllure2ReporterOptions = {
5
+ testCase: {
6
+ labels: {
7
+ package: ({ filePath }) => filePath.slice(1).join('/'),
8
+ testMethod: ({ testCase }) => testCase.fullName,
9
+ tag: ['unit'],
10
+ },
11
+ },
12
+ };
13
+
14
+ /** @type {import('@jest/types').Config.InitialOptions} */
15
+ module.exports = {
16
+ setupFiles: [
17
+ '<rootDir>/__tests__/setupJest.js'
18
+ ],
19
+ testEnvironment: DEBUG ? 'node' : 'jest-allure2-reporter/environment-node',
20
+ testRunner: 'jest-circus/runner',
21
+ roots: [
22
+ 'node_modules',
23
+ 'local-cli',
24
+ 'src',
25
+ 'runners'
26
+ ],
27
+ testPathIgnorePatterns: [
28
+ '/node_modules/',
29
+ 'local-cli/test.js'
30
+ ],
31
+ coveragePathIgnorePatterns: [
32
+ '/node_modules/',
33
+ '__tests__',
34
+ '.test.js$',
35
+ '.mock.js$',
36
+ 'index.js',
37
+ 'internals.js',
38
+ 'local-cli/utils',
39
+ 'src/environmentFactory',
40
+ 'src/android/espressoapi',
41
+ 'src/artifacts/factories/index.js',
42
+ 'src/artifacts/providers/index.js',
43
+ 'src/artifacts/log',
44
+ 'src/artifacts/screenshot',
45
+ 'src/artifacts/video',
46
+ 'src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js',
47
+ 'src/devices/allocation/drivers/android/emulator/patchAvdSkinConfig.js',
48
+ 'src/devices/allocation/.*AllocDriver.js',
49
+ 'src/devices/allocation/drivers/ios',
50
+ 'src/devices/allocation/factories',
51
+ 'src/devices/allocation/factories/drivers',
52
+ 'src/devices/cookies',
53
+ 'src/devices/common/drivers/android/exec/ADB.js',
54
+ 'src/devices/common/drivers/android/emulator/exec/EmulatorExec.js',
55
+ 'src/devices/common/drivers/android/tools/EmulatorTelnet.js',
56
+ 'src/devices/common/drivers/ios/tools',
57
+ 'src/devices/runtime/drivers/android/AndroidDriver.js',
58
+ 'src/devices/runtime/drivers/android/emulator/EmulatorDriver.js',
59
+ 'src/devices/runtime/drivers/DeviceDriverBase.js',
60
+ 'src/devices/runtime/drivers/ios',
61
+ 'src/devices/runtime/factories',
62
+ 'src/devices/runtime/factories/drivers',
63
+ 'src/devices/validation/EnvironmentValidatorBase.js',
64
+ 'src/devices/validation/factories',
65
+ 'src/matchers/factories',
66
+ 'src/utils/appdatapath.js',
67
+ 'src/utils/debug.js',
68
+ 'src/utils/environment.js',
69
+ 'src/utils/logger.js',
70
+ 'src/utils/pipeCommands.js',
71
+ 'src/utils/pressAnyKey.js',
72
+ 'src/utils/shellUtils.js',
73
+ 'runners/jest/reporters',
74
+ 'runners/jest/testEnvironment',
75
+ 'src/DetoxWorker.js',
76
+ 'src/logger/utils/streamUtils.js',
77
+ 'src/realms'
78
+ ],
79
+ resetMocks: true,
80
+ resetModules: true,
81
+ reporters: [
82
+ 'default',
83
+ [
84
+ 'jest-allure2-reporter',
85
+ jestAllure2ReporterOptions,
86
+ ]
87
+ ],
88
+ coverageReporters: [
89
+ 'html',
90
+ 'json',
91
+ 'text',
92
+ 'clover',
93
+ [
94
+ 'lcov',
95
+ {
96
+ projectRoot: '..'
97
+ }
98
+ ]
99
+ ],
100
+ coverageThreshold: {
101
+ global: {
102
+ statements: 100,
103
+ branches: 100,
104
+ functions: 100,
105
+ lines: 100
106
+ }
107
+ }
108
+ };
@@ -1,16 +1,12 @@
1
1
  const { log } = require('../internals');
2
- const DeviceRegistry = require('../src/devices/DeviceRegistry');
3
- const { getDetoxLibraryRootPath } = require('../src/utils/environment');
4
-
2
+ const DeviceRegistry = require('../src/devices/allocation/DeviceRegistry');
5
3
 
6
4
  module.exports.command = 'reset-lock-file';
7
- module.exports.desc = 'Resets all Detox lock files. Useful when you need to run multiple `detox test` commands in parallel with --keepLockFile.';
5
+ module.exports.desc = 'Resets Detox lock file completely - all devices are marked as available after that.';
8
6
 
9
7
  module.exports.handler = async function resetLockFile() {
10
- await Promise.all([
11
- DeviceRegistry.forIOS().reset(),
12
- DeviceRegistry.forAndroid().reset(),
13
- ]);
8
+ const registry = new DeviceRegistry();
9
+ await registry.reset();
14
10
 
15
- log.info(`Cleaned lock files from: ${getDetoxLibraryRootPath()}`);
11
+ log.info(`Cleaned lock file at: ${registry.lockFilePath}`);
16
12
  };
@@ -12,6 +12,7 @@ const { escapeSpaces, useForwardSlashes } = require('../../src/utils/shellUtils'
12
12
  const sleep = require('../../src/utils/sleep');
13
13
  const AppStartCommand = require('../startCommand/AppStartCommand');
14
14
  const { markErrorAsLogged } = require('../utils/cliErrorHandling');
15
+ const interruptListeners = require('../utils/interruptListeners');
15
16
 
16
17
  const TestRunnerError = require('./TestRunnerError');
17
18
 
@@ -28,10 +29,12 @@ class TestRunnerCommand {
28
29
  const appsConfig = opts.config.apps;
29
30
 
30
31
  this._argv = runnerConfig.args;
32
+ this._detached = runnerConfig.detached;
31
33
  this._retries = runnerConfig.retries;
32
34
  this._envHint = this._buildEnvHint(opts.env);
33
35
  this._startCommands = this._prepareStartCommands(appsConfig, cliConfig);
34
36
  this._envFwd = {};
37
+ this._terminating = false;
35
38
 
36
39
  if (runnerConfig.forwardEnv) {
37
40
  this._envFwd = this._buildEnvOverride(cliConfig, deviceConfig);
@@ -59,16 +62,20 @@ class TestRunnerCommand {
59
62
  } catch (e) {
60
63
  launchError = e;
61
64
 
65
+ if (this._terminating) {
66
+ runsLeft = 0;
67
+ }
68
+
62
69
  const failedTestFiles = detox.session.testResults.filter(r => !r.success);
63
70
 
64
71
  const { bail } = detox.config.testRunner;
65
72
  if (bail && failedTestFiles.some(r => r.isPermanentFailure)) {
66
- throw e;
73
+ runsLeft = 0;
67
74
  }
68
75
 
69
76
  const testFilesToRetry = failedTestFiles.filter(r => !r.isPermanentFailure).map(r => r.testFilePath);
70
- if (_.isEmpty(testFilesToRetry)) {
71
- throw e;
77
+ if (testFilesToRetry.length === 0) {
78
+ runsLeft = 0;
72
79
  }
73
80
 
74
81
  if (--runsLeft > 0) {
@@ -143,6 +150,15 @@ class TestRunnerCommand {
143
150
  }, _.isUndefined);
144
151
  }
145
152
 
153
+ _onTerminate = () => {
154
+ if (this._terminating) {
155
+ return;
156
+ }
157
+
158
+ this._terminating = true;
159
+ return detox.unsafe_conductEarlyTeardown(true);
160
+ };
161
+
146
162
  async _spawnTestRunner() {
147
163
  const fullCommand = this._buildSpawnArguments().map(escapeSpaces);
148
164
  const fullCommandWithHint = printEnvironmentVariables(this._envHint) + fullCommand.join(' ');
@@ -153,6 +169,7 @@ class TestRunnerCommand {
153
169
  cp.spawn(fullCommand[0], fullCommand.slice(1), {
154
170
  shell: true,
155
171
  stdio: 'inherit',
172
+ detached: this._detached,
156
173
  env: _({})
157
174
  .assign(process.env)
158
175
  .assign(this._envFwd)
@@ -162,6 +179,8 @@ class TestRunnerCommand {
162
179
  })
163
180
  .on('error', /* istanbul ignore next */ (err) => reject(err))
164
181
  .on('exit', (code, signal) => {
182
+ interruptListeners.unsubscribe(this._onTerminate);
183
+
165
184
  if (code === 0) {
166
185
  log.trace.end({ success: true });
167
186
  resolve();
@@ -175,6 +194,10 @@ class TestRunnerCommand {
175
194
  reject(markErrorAsLogged(error));
176
195
  }
177
196
  });
197
+
198
+ if (this._detached) {
199
+ interruptListeners.subscribe(this._onTerminate);
200
+ }
178
201
  });
179
202
  }
180
203
 
@@ -0,0 +1,15 @@
1
+ function subscribe(listener) {
2
+ process.on('SIGINT', listener);
3
+ process.on('SIGTERM', listener);
4
+ }
5
+
6
+ function unsubscribe(listener) {
7
+ process.removeListener('SIGINT', listener);
8
+ process.removeListener('SIGTERM', listener);
9
+ }
10
+
11
+ module.exports = {
12
+ subscribe,
13
+ unsubscribe,
14
+ };
15
+
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": "21.0.0-rc.6",
4
+ "version": "21.0.0-rc.7",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -51,7 +51,6 @@
51
51
  "eslint-plugin-node": "^11.1.0",
52
52
  "eslint-plugin-unicorn": "^47.0.0",
53
53
  "jest": "^28.1.3",
54
- "jest-allure2-reporter": "^1.2.1",
55
54
  "mockdate": "^2.0.1",
56
55
  "prettier": "^2.4.1",
57
56
  "react-native": "0.71.10",
@@ -107,105 +106,8 @@
107
106
  "engines": {
108
107
  "node": ">=14.5.0"
109
108
  },
110
- "jest": {
111
- "setupFiles": [
112
- "<rootDir>/__tests__/setupJest.js"
113
- ],
114
- "testEnvironment": "node",
115
- "testRunner": "jest-circus/runner",
116
- "roots": [
117
- "node_modules",
118
- "local-cli",
119
- "src",
120
- "runners"
121
- ],
122
- "testPathIgnorePatterns": [
123
- "/node_modules/",
124
- "local-cli/test.js"
125
- ],
126
- "coveragePathIgnorePatterns": [
127
- "/node_modules/",
128
- "__tests__",
129
- ".test.js$",
130
- ".mock.js$",
131
- "index.js",
132
- "internals.js",
133
- "local-cli/utils",
134
- "src/environmentFactory",
135
- "src/android/espressoapi",
136
- "src/artifacts/factories/index.js",
137
- "src/artifacts/providers/index.js",
138
- "src/artifacts/log",
139
- "src/artifacts/screenshot",
140
- "src/artifacts/video",
141
- "src/devices/allocation/drivers/AllocationDriverBase.js",
142
- "src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js",
143
- "src/devices/allocation/drivers/android/emulator/patchAvdSkinConfig.js",
144
- "src/devices/allocation/drivers/ios",
145
- "src/devices/allocation/factories",
146
- "src/devices/allocation/factories/drivers",
147
- "src/devices/cookies",
148
- "src/devices/common/drivers/android/exec/ADB.js",
149
- "src/devices/common/drivers/android/emulator/exec/EmulatorExec.js",
150
- "src/devices/common/drivers/android/tools/EmulatorTelnet.js",
151
- "src/devices/common/drivers/ios/tools",
152
- "src/devices/runtime/drivers/android/AndroidDriver.js",
153
- "src/devices/runtime/drivers/android/emulator/EmulatorDriver.js",
154
- "src/devices/runtime/drivers/DeviceDriverBase.js",
155
- "src/devices/runtime/drivers/ios",
156
- "src/devices/runtime/factories",
157
- "src/devices/runtime/factories/drivers",
158
- "src/matchers/factories",
159
- "src/validation/EnvironmentValidatorBase.js",
160
- "src/validation/factories",
161
- "src/validation/ios/IosSimulatorEnvValidator",
162
- "src/utils/appdatapath.js",
163
- "src/utils/debug.js",
164
- "src/utils/environment.js",
165
- "src/utils/logger.js",
166
- "src/utils/pipeCommands.js",
167
- "src/utils/pressAnyKey.js",
168
- "src/utils/shellUtils.js",
169
- "runners/jest/reporters",
170
- "runners/jest/testEnvironment",
171
- "src/DetoxWorker.js",
172
- "src/logger/utils/streamUtils.js",
173
- "src/realms"
174
- ],
175
- "resetMocks": true,
176
- "resetModules": true,
177
- "reporters": [
178
- "default",
179
- [
180
- "jest-allure2-reporter",
181
- {
182
- "getEnvironmentInfo": false
183
- }
184
- ]
185
- ],
186
- "coverageReporters": [
187
- "html",
188
- "json",
189
- "text",
190
- "clover",
191
- [
192
- "lcov",
193
- {
194
- "projectRoot": ".."
195
- }
196
- ]
197
- ],
198
- "coverageThreshold": {
199
- "global": {
200
- "statements": 100,
201
- "branches": 100,
202
- "functions": 100,
203
- "lines": 100
204
- }
205
- }
206
- },
207
109
  "browserslist": [
208
110
  "node 14"
209
111
  ],
210
- "gitHead": "1a6418e78c4657001a6db255f2b3972baab8bee6"
112
+ "gitHead": "3aebb232c3e8d2d4d0446e5ee237701626d1922f"
211
113
  }
@@ -1 +1,21 @@
1
- module.exports = require('./reporters/DetoxReporter');
1
+ /** @typedef {import('@jest/reporters').Reporter} Reporter */
2
+
3
+ const {
4
+ DetoxIPCReporter,
5
+ DetoxReporterDispatcher,
6
+ DetoxSummaryReporter,
7
+ DetoxVerboseReporter,
8
+ } = require('./reporters');
9
+
10
+ /** @implements {Reporter} */
11
+ class DetoxReporter extends DetoxReporterDispatcher {
12
+ constructor(globalConfig) {
13
+ super(globalConfig, {
14
+ DetoxSummaryReporter,
15
+ DetoxVerboseReporter,
16
+ DetoxIPCReporter,
17
+ });
18
+ }
19
+ }
20
+
21
+ module.exports = DetoxReporter;
@@ -0,0 +1,34 @@
1
+ const { config, reportTestResults } = require('../../../internals');
2
+
3
+ /** @typedef {import('@jest/reporters').Reporter} Reporter */
4
+
5
+ /** @implements {Partial<Reporter>} */
6
+ class DetoxIPCReporter {
7
+ /**
8
+ * @param {Set<import('@jest/reporters').TestContext>} testContexts
9
+ * @param {import('@jest/reporters').AggregatedResult} aggregatedResult
10
+ */
11
+ async onRunComplete(testContexts, aggregatedResult) {
12
+ const lostTests = aggregatedResult.numTotalTestSuites - aggregatedResult.testResults.length;
13
+
14
+ await reportTestResults(aggregatedResult.testResults.map(r => ({
15
+ success: !r.failureMessage,
16
+ testFilePath: r.testFilePath,
17
+ testExecError: r.testExecError,
18
+ isPermanentFailure: lostTests > 0 || this._isPermanentFailure(r),
19
+ })));
20
+ }
21
+
22
+ /**
23
+ * @param {import('@jest/test-result').TestResult} testResult
24
+ */
25
+ _isPermanentFailure(testResult) {
26
+ if (config.testRunner.jest.retryAfterCircusRetries) {
27
+ return false;
28
+ }
29
+
30
+ return testResult.testResults.some(r => r.status === 'failed' && r.invocations > 1);
31
+ }
32
+ }
33
+
34
+ module.exports = DetoxIPCReporter;
@@ -0,0 +1,144 @@
1
+ /** @typedef {import('@jest/reporters').Reporter} Reporter */
2
+
3
+ const { config, unsafe_conductEarlyTeardown } = require('../../../internals');
4
+ const Deferred = require('../../../src/utils/Deferred');
5
+
6
+ /** @implements {Reporter} */
7
+ class DetoxReporterDispatcher {
8
+ /**
9
+ * @param {import('@jest/types').Config.GlobalConfig} globalConfig
10
+ * @param {Record<string, new (globalConfig: import('@jest/types').Config.GlobalConfig) => Partial<Reporter>>} reporters
11
+ */
12
+ constructor(globalConfig, reporters) {
13
+ this._bail = globalConfig.bail;
14
+ /** @type {Deferred | null} */
15
+ this._lastRunComplete = null;
16
+ /** @type {Set<string>} */
17
+ this._pendingTestFiles = new Set();
18
+ /** @type {Promise<any> | null} */
19
+ this._onRunCompletePromise = null;
20
+ /** @type {Partial<Reporter>[]} */
21
+ this._reporters = Object.values(reporters).map((Reporter) => new Reporter(globalConfig));
22
+ }
23
+
24
+ getLastError() {
25
+ for (const reporter of this._reporters) {
26
+ let error = typeof reporter.getLastError === 'function'
27
+ ? reporter.getLastError()
28
+ : undefined;
29
+
30
+ if (error) {
31
+ return error;
32
+ }
33
+ }
34
+
35
+ return;
36
+ }
37
+
38
+ onRunStart(aggregatedResult, options) {
39
+ return this._dispatch('onRunStart', aggregatedResult, options);
40
+ }
41
+
42
+ onTestFileStart(test) {
43
+ this._pendingTestFiles.add(test.path);
44
+ return this._dispatch(['onTestFileStart', 'onTestStart'], test);
45
+ }
46
+
47
+ onTestStart(test) {
48
+ // Legacy method
49
+ return this.onTestFileStart(test);
50
+ }
51
+
52
+ // NEW! Supported only since Jest 29.6.0
53
+ onTestCaseStart(test, testCaseStartInfo) {
54
+ return this._dispatch('onTestCaseStart', test, testCaseStartInfo);
55
+ }
56
+
57
+ onTestCaseResult(test, testCaseResult) {
58
+ return this._dispatch('onTestCaseResult', test, testCaseResult);
59
+ }
60
+
61
+ async onTestFileResult(test, testResult, aggregatedResult) {
62
+ this._pendingTestFiles.delete(test.path);
63
+
64
+ await this._dispatch(['onTestFileResult', 'onTestResult'], test, testResult, aggregatedResult);
65
+
66
+ if (this._lastRunComplete && this._pendingTestFiles.size === 0) {
67
+ this._lastRunComplete.resolve(aggregatedResult);
68
+ }
69
+ }
70
+
71
+ onTestResult(test, testResult, aggregatedResult) {
72
+ // Legacy method
73
+ return this.onTestFileResult(test, testResult, aggregatedResult);
74
+ }
75
+
76
+ onRunComplete(testContexts, aggregatedResult) {
77
+ if (!this._lastRunComplete) {
78
+ // Both `_lastRunComplete` and `_onRunCompletePromise` are used to prevent
79
+ // a bug in Jest, where `onRunComplete` is called multiple times when
80
+ // Jest runs with `--bail` and multiple workers, and `onRunComplete`
81
+ // is implemented as an asynchronous long-running operation.
82
+ this._lastRunComplete = this._pendingTestFiles.size === 0
83
+ ? Deferred.resolved(aggregatedResult)
84
+ : new Deferred();
85
+ }
86
+
87
+ if (!this._onRunCompletePromise) {
88
+ this._onRunCompletePromise = this._doRunComplete(testContexts, aggregatedResult);
89
+ }
90
+
91
+ return this._onRunCompletePromise;
92
+ }
93
+
94
+ /**
95
+ * @private
96
+ * @param {Set<import('@jest/reporters').TestContext>} testContexts
97
+ * @param {import('@jest/test-result').AggregatedResult} aggregatedResult
98
+ * @returns {Promise<void>}
99
+ */
100
+ async _doRunComplete(testContexts, aggregatedResult) {
101
+ const earlyTeardown = this._bail > 0 && aggregatedResult.numFailedTests >= this._bail;
102
+ if (earlyTeardown) {
103
+ const lostTests = aggregatedResult.numTotalTestSuites - aggregatedResult.testResults.length;
104
+ if (lostTests > 0 && config.testRunner.retries > 0) {
105
+ console.warn(
106
+ 'Jest aborted the test execution before all scheduled test files have been reported.\n' +
107
+ 'If you want to retry the whole test run, please disable Jest\'s --bail option.'
108
+ );
109
+ }
110
+
111
+ await unsafe_conductEarlyTeardown();
112
+ }
113
+
114
+ await this._lastRunComplete.promise;
115
+ await this._dispatch('onRunComplete', testContexts, aggregatedResult);
116
+ }
117
+
118
+ /**
119
+ * @private
120
+ * @param {string | string[]} rawMethodNames
121
+ * @param {...any} args
122
+ * @returns {Promise<void>}
123
+ */
124
+ _dispatch(rawMethodNames, ...args) {
125
+ const methodNames = Array.isArray(rawMethodNames)
126
+ ? rawMethodNames
127
+ : [rawMethodNames];
128
+
129
+ const maybePromises = [];
130
+
131
+ for (const reporter of this._reporters) {
132
+ for (const methodName of methodNames) {
133
+ if (typeof reporter[methodName] === 'function') {
134
+ maybePromises.push(reporter[methodName](...args));
135
+ break;
136
+ }
137
+ }
138
+ }
139
+
140
+ return Promise.all(maybePromises).then(() => void 0);
141
+ }
142
+ }
143
+
144
+ module.exports = DetoxReporterDispatcher;
@@ -0,0 +1,16 @@
1
+ /** @typedef {import('@jest/reporters').Reporter} Reporter */
2
+
3
+ const resolveFrom = require('resolve-from');
4
+ /** @type {new (globalConfig: any) => import('@jest/reporters').SummaryReporter} */
5
+ const SummaryReporter = require(resolveFrom(process.cwd(), '@jest/reporters')).SummaryReporter;
6
+
7
+ /** @implements {Partial<Reporter>} */
8
+ class DetoxSummaryReporter {
9
+ constructor(globalConfig) {
10
+ if (globalConfig.reporters.every(([name]) => name !== 'default' && name !== 'summary')) {
11
+ return new SummaryReporter(globalConfig);
12
+ }
13
+ }
14
+ }
15
+
16
+ module.exports = DetoxSummaryReporter;
@@ -0,0 +1,16 @@
1
+ /** @typedef {import('@jest/reporters').Reporter} Reporter */
2
+
3
+ const resolveFrom = require('resolve-from');
4
+ /** @type {new (globalConfig: any) => import('@jest/reporters').VerboseReporter} */
5
+ const VerboseReporter = require(resolveFrom(process.cwd(), '@jest/reporters')).VerboseReporter;
6
+
7
+ /** @implements {Partial<Reporter>} */
8
+ class DetoxVerboseReporter {
9
+ constructor(globalConfig) {
10
+ if (globalConfig.reporters.every(([name]) => name !== 'default')) {
11
+ return new VerboseReporter(globalConfig);
12
+ }
13
+ }
14
+ }
15
+
16
+ module.exports = DetoxVerboseReporter;
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ DetoxIPCReporter: require('./DetoxIPCReporter'),
3
+ DetoxReporterDispatcher: require('./DetoxReporterDispatcher'),
4
+ DetoxSummaryReporter: require('./DetoxSummaryReporter'),
5
+ DetoxVerboseReporter: require('./DetoxVerboseReporter'),
6
+ };
@@ -70,7 +70,14 @@ class DetoxCircusEnvironment extends NodeEnvironment {
70
70
  await this.initDetox();
71
71
  }
72
72
 
73
+ // @ts-expect-error TS2425
73
74
  async handleTestEvent(event, state) {
75
+ if (detox.session.unsafe_earlyTeardown) {
76
+ if (event.name === 'test_fn_start' || event.name === 'hook_start') {
77
+ throw new Error('Detox halted test execution due to an early teardown request');
78
+ }
79
+ }
80
+
74
81
  this._timer.schedule(state.testTimeout != null ? state.testTimeout : this.setupTimeout);
75
82
 
76
83
  if (SYNC_CIRCUS_EVENTS.has(event.name)) {
@@ -102,6 +109,10 @@ class DetoxCircusEnvironment extends NodeEnvironment {
102
109
  * @protected
103
110
  */
104
111
  async initDetox() {
112
+ if (detox.session.unsafe_earlyTeardown) {
113
+ throw new Error('Detox halted test execution due to an early teardown request');
114
+ }
115
+
105
116
  const opts = {
106
117
  global: this.global,
107
118
  workerId: `w${process.env.JEST_WORKER_ID}`,