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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. package/Detox-android/com/wix/detox/{20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-javadoc.jar → 20.0.0/detox-20.0.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-sources.jar → 20.0.0/detox-20.0.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.pom → 20.0.0/detox-20.0.0.pom} +2 -8
  17. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.0/detox-20.0.0.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 +13 -8
  30. package/android/detox/build.gradle +14 -10
  31. package/android/detox/proguard-rules-app.pro +6 -0
  32. package/android/detox/proguard-rules.pro +3 -0
  33. package/android/detox/publish-pom.gradle +5 -1
  34. package/android/detox/publishing.gradle +35 -33
  35. package/android/detox/src/full/java/com/wix/detox/DetoxCrashHandler.kt +1 -1
  36. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  37. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +1 -1
  38. package/android/detox/src/full/java/com/wix/detox/adapters/server/WebSocketClient.java +3 -1
  39. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +1 -3
  40. package/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java +1 -1
  41. package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +22 -0
  42. package/android/detox/src/{main → full}/java/com/wix/detox/espresso/action/GetAttributesAction.kt +13 -1
  43. package/android/detox/src/full/java/com/wix/detox/espresso/common/SliderHelper.kt +75 -0
  44. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewMatchers.kt +16 -23
  45. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
  46. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
  47. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt +54 -8
  48. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/IdlingResourceDescription.kt +19 -13
  49. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +33 -30
  50. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +7 -27
  51. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +1 -11
  52. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +13 -4
  53. package/android/detox/src/main/java/com/wix/detox/common/DetoxErrors.java +4 -1
  54. package/android/detox/src/main/java/com/wix/detox/common/TextFileReader.kt +1 -1
  55. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +2 -1
  56. package/android/detox/src/main/java/com/wix/detox/espresso/action/common/ReflectUtils.kt +10 -0
  57. package/android/detox/src/main/java/com/wix/detox/espresso/action/common/utils/UiControllerUtils.kt +1 -1
  58. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/DetoxMultiTapSpec.kt +4 -3
  59. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +15 -3
  60. package/android/detox/src/testFull/java/com/wix/detox/espresso/common/SliderHelperTest.kt +39 -0
  61. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +61 -0
  62. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +3 -11
  63. package/android/gradle/wrapper/gradle-wrapper.properties +2 -1
  64. package/android/gradlew +181 -107
  65. package/index.d.ts +198 -57
  66. package/internals.d.ts +220 -51
  67. package/local-cli/build.js +2 -2
  68. package/local-cli/build.test.js +14 -14
  69. package/local-cli/cli.js +8 -6
  70. package/local-cli/init.js +61 -21
  71. package/local-cli/rebuild-framework-cache.js +1 -1
  72. package/local-cli/reset-lock-file.js +16 -0
  73. package/local-cli/templates/jest.js +13 -10
  74. package/local-cli/test.js +14 -8
  75. package/local-cli/test.test.js +148 -61
  76. package/local-cli/testCommand/TestRunnerCommand.js +78 -71
  77. package/local-cli/testCommand/builder.js +0 -1
  78. package/local-cli/testCommand/middlewares.js +4 -13
  79. package/local-cli/testCommand/warnings.js +0 -3
  80. package/local-cli/utils/jestInternals.js +4 -1
  81. package/package.json +22 -15
  82. package/runners/deprecation.js +42 -44
  83. package/runners/jest/globalSetup.js +1 -1
  84. package/runners/jest/globalTeardown.js +1 -1
  85. package/runners/jest/index.d.ts +60 -0
  86. package/runners/jest/index.js +3 -8
  87. package/runners/jest/index.test.js +13 -0
  88. package/runners/jest/reporters/DetoxReporter.js +33 -2
  89. package/runners/jest/testEnvironment/index.js +119 -69
  90. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +94 -51
  91. package/runners/jest/testEnvironment/listeners/DetoxPlatformFilterListener.js +1 -1
  92. package/runners/jest/testEnvironment/listeners/SpecReporter.js +14 -16
  93. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +2 -6
  94. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  95. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -1
  96. package/src/DetoxWorker.js +107 -59
  97. package/src/android/core/NativeElement.js +56 -20
  98. package/src/android/core/NativeExpect.js +28 -9
  99. package/src/android/interactions/native.js +25 -18
  100. package/src/artifacts/ArtifactsManager.js +14 -47
  101. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  102. package/src/artifacts/log/android/ADBLogcatRecording.js +11 -28
  103. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  104. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  105. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  106. package/src/artifacts/templates/plugin/ArtifactPlugin.js +1 -1
  107. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  108. package/src/artifacts/utils/temporaryPath.js +18 -7
  109. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  110. package/src/client/AsyncWebSocket.js +8 -17
  111. package/src/client/Client.js +19 -2
  112. package/src/client/actions/formatters/sync-resources/NetworkFormatter.js +1 -1
  113. package/src/configuration/collectCliConfig.js +1 -12
  114. package/src/configuration/composeAppsConfig.js +5 -1
  115. package/src/configuration/composeDeviceConfig.js +1 -1
  116. package/src/configuration/composeLoggerConfig.js +19 -10
  117. package/src/configuration/composeRunnerConfig.js +62 -9
  118. package/src/configuration/index.js +14 -9
  119. package/src/configuration/loadExternalConfig.js +1 -1
  120. package/src/devices/allocation/DeviceAllocator.js +3 -2
  121. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +5 -5
  122. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +4 -3
  123. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  124. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -2
  125. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  126. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +1 -1
  127. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +1 -0
  128. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  129. package/src/devices/common/drivers/android/exec/ADB.js +5 -0
  130. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  131. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  132. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  133. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  134. package/src/devices/common/drivers/android/tools/MonitoredInstrumentation.js +1 -1
  135. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +29 -3
  136. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +13 -15
  137. package/src/devices/runtime/RuntimeDevice.js +19 -12
  138. package/src/devices/runtime/drivers/DeviceDriverBase.js +1 -1
  139. package/src/devices/runtime/drivers/android/AndroidDriver.js +10 -2
  140. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +1 -1
  141. package/src/errors/DetoxConfigErrorComposer.js +18 -3
  142. package/src/ios/expectTwo.js +153 -67
  143. package/src/ipc/IPCClient.js +12 -12
  144. package/src/ipc/IPCServer.js +34 -17
  145. package/src/ipc/{state.js → SessionState.js} +26 -31
  146. package/src/logger/DetoxLogger.js +261 -157
  147. package/src/logger/index.js +5 -0
  148. package/src/logger/utils/BunyanLogger.js +76 -0
  149. package/src/logger/utils/CategoryThreadDispatcher.js +36 -0
  150. package/src/logger/utils/DetoxLogFinalizer.js +140 -0
  151. package/src/logger/utils/MessageStack.js +24 -0
  152. package/src/logger/utils/ThreadDispatcher.js +61 -0
  153. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +5 -4
  154. package/src/logger/utils/sanitizeBunyanContext.js +30 -0
  155. package/src/{utils → logger/utils}/streamUtils.js +51 -17
  156. package/src/logger/utils/tracerLegacy.js +37 -0
  157. package/src/realms/DetoxContext.js +78 -65
  158. package/src/realms/DetoxInternalsFacade.js +8 -12
  159. package/src/realms/DetoxPrimaryContext.js +106 -73
  160. package/src/realms/DetoxSecondaryContext.js +29 -31
  161. package/src/server/DetoxConnection.js +18 -23
  162. package/src/server/DetoxServer.js +7 -10
  163. package/src/server/DetoxSession.js +6 -6
  164. package/src/server/DetoxSessionManager.js +1 -1
  165. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  166. package/src/symbols.js +16 -22
  167. package/src/utils/Timer.js +55 -38
  168. package/src/utils/argparse.js +11 -0
  169. package/src/utils/childProcess/exec.js +1 -1
  170. package/src/utils/childProcess/spawn.js +1 -1
  171. package/src/utils/environment.js +30 -15
  172. package/src/utils/errorUtils.js +24 -3
  173. package/src/utils/invocationTraceDescriptions.js +43 -0
  174. package/src/utils/logger.js +1 -1
  175. package/src/utils/traceInvocationCall.js +21 -0
  176. package/src/utils/traceMethods.js +15 -0
  177. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  178. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  179. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  180. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  181. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  182. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  183. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  184. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  185. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.aar +0 -0
  186. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.aar.md5 +0 -1
  187. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.aar.sha1 +0 -1
  188. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.aar.sha256 +0 -1
  189. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.aar.sha512 +0 -1
  190. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  191. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  192. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  193. package/Detox-android/com/wix/detox/20.0.0-breaking.new-global-lifecycle.0/detox-20.0.0-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  194. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategy.kt +0 -84
  195. package/android/detox/src/main/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +0 -36
  196. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/AdjustSliderToPositionActionTest.kt +0 -59
  197. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +0 -115
  198. package/runners/jest/deprecation.js +0 -25
  199. package/src/configuration/utils/warnings.js +0 -12
  200. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  201. package/src/logger/DetoxTracer.js +0 -133
  202. package/src/logger/TraceThreadDispatcher.js +0 -52
  203. package/src/utils/ChromeTracingExporter.js +0 -53
  204. package/src/utils/trace.js +0 -19
@@ -1,15 +1,19 @@
1
+ const { uniqBy } = require('lodash');
1
2
  const { IPC } = require('node-ipc');
2
3
 
4
+ const { serializeObjectWithError } = require('../utils/errorUtils');
5
+
3
6
  class IPCServer {
4
7
  /**
5
8
  * @param {object} options
6
- * @param {import('./state').PrimarySessionState} options.sessionState
9
+ * @param {import('./SessionState')} options.sessionState
7
10
  * @param {Detox.Logger} options.logger
8
11
  */
9
12
  constructor({ sessionState, logger }) {
10
13
  this._sessionState = sessionState;
11
- this._logger = logger.child({ __filename, cat: 'ipc' });
14
+ this._logger = logger.child({ cat: 'ipc,ipc-server' });
12
15
  this._ipc = null;
16
+ this._workers = new Set();
13
17
  }
14
18
 
15
19
  get id() {
@@ -26,12 +30,12 @@ class IPCServer {
26
30
  this._ipc.config.appspace = 'detox.';
27
31
  this._ipc.config.logger = (msg) => this._logger.trace(msg);
28
32
 
29
- await new Promise((resolve) => {
33
+ await new Promise((resolve) => {
30
34
  // TODO: handle reject
31
35
  this._ipc.serve(() => resolve());
32
36
  this._ipc.server.on('registerContext', this.onRegisterContext.bind(this));
33
37
  this._ipc.server.on('registerWorker', this.onRegisterWorker.bind(this));
34
- this._ipc.server.on('failedTests', this.onFailedTests.bind(this));
38
+ this._ipc.server.on('reportTestResults', this.onReportTestResults.bind(this));
35
39
  this._ipc.server.start();
36
40
  });
37
41
  }
@@ -48,33 +52,46 @@ class IPCServer {
48
52
  });
49
53
  }
50
54
 
51
- onRegisterContext({ id, logFile }, socket) {
55
+ onRegisterContext({ id }, socket) {
52
56
  this._sessionState.contexts.push(id);
53
57
 
54
- if (logFile && !this._sessionState.logFiles.includes(logFile)) {
55
- this._sessionState.logFiles.push(logFile);
56
- }
57
-
58
- this._ipc.server.emit(socket, 'registerContextDone', {});
58
+ this._ipc.server.emit(socket, 'registerContextDone', {
59
+ testResults: this._sessionState.testResults,
60
+ testSessionIndex: this._sessionState.testSessionIndex,
61
+ });
59
62
  }
60
63
 
61
- onRegisterWorker({ workerId }, socket) {
64
+ onRegisterWorker({ workerId }, socket = null) {
65
+ const workersCount = this._workers.add(workerId).size;
66
+ const shouldBroadcast = workersCount > this._sessionState.workersCount;
67
+ this._sessionState.workersCount = workersCount;
68
+
62
69
  if (socket) {
63
- this._ipc.server.emit(socket, 'registerWorkerDone', {});
70
+ this._ipc.server.emit(socket, 'registerWorkerDone', { workersCount });
64
71
  }
65
72
 
66
- if (workerId > this._sessionState.workersCount) {
67
- const workersCount = this._sessionState.workersCount = workerId;
73
+ if (shouldBroadcast) {
68
74
  this._ipc.server.broadcast('sessionStateUpdate', { workersCount });
69
75
  }
70
76
  }
71
77
 
72
- onFailedTests({ testFilePaths }, socket) {
73
- this._sessionState.failedTestFiles.push(...testFilePaths);
78
+ onReportTestResults({ testResults }, socket = null) {
79
+ const merged = uniqBy([
80
+ ...testResults.map(r => serializeObjectWithError(r, 'testExecError')),
81
+ ...this._sessionState.testResults
82
+ ], 'testFilePath');
83
+
84
+ this._sessionState.testResults.splice(0, Infinity, ...merged);
74
85
 
75
86
  if (socket) {
76
- this._ipc.server.emit(socket, 'failedTestsDone', {});
87
+ this._ipc.server.emit(socket, 'reportTestResultsDone', {
88
+ testResults: this._sessionState.testResults,
89
+ });
77
90
  }
91
+
92
+ this._ipc.server.broadcast('sessionStateUpdate', {
93
+ testResults: this._sessionState.testResults,
94
+ });
78
95
  }
79
96
  }
80
97
 
@@ -1,8 +1,30 @@
1
+ const vm = require('vm');
2
+
1
3
  const cycle = require('json-cycle');
2
4
 
3
- const uuid = require('../utils/uuid');
5
+ const context = vm.createContext({ require }, {
6
+ name: 'VM User Context',
7
+ });
4
8
 
5
9
  class SessionState {
10
+ constructor({
11
+ id = '',
12
+ contexts = [],
13
+ detoxConfig = null,
14
+ detoxIPCServer = '',
15
+ testResults = [],
16
+ testSessionIndex = 0,
17
+ workersCount = 0
18
+ }) {
19
+ this.id = id;
20
+ this.contexts = contexts;
21
+ this.detoxConfig = detoxConfig;
22
+ this.detoxIPCServer = detoxIPCServer;
23
+ this.testResults = testResults;
24
+ this.testSessionIndex = testSessionIndex;
25
+ this.workersCount = workersCount;
26
+ }
27
+
6
28
  patch(state) {
7
29
  Object.assign(this, state);
8
30
  }
@@ -21,8 +43,8 @@ class SessionState {
21
43
  }
22
44
 
23
45
  static reviver(key, val) {
24
- if (typeof val === 'object' && typeof val.$fn == 'string') {
25
- return eval(val.$fn);
46
+ if (typeof val === 'object' && val !== null && typeof val.$fn == 'string') {
47
+ return vm.runInContext(val.$fn, context);
26
48
  } else {
27
49
  return val;
28
50
  }
@@ -37,31 +59,4 @@ class SessionState {
37
59
  }
38
60
  }
39
61
 
40
- class SecondarySessionState extends SessionState {
41
- constructor({ id = uuid.UUID(), detoxConfigSnapshotPath = '', detoxConfig = null, detoxIPCServer = '', workerId = undefined, workersCount = 0 }) {
42
- super();
43
-
44
- this.id = id;
45
- this.detoxConfigSnapshotPath = detoxConfigSnapshotPath;
46
- this.detoxConfig = detoxConfig;
47
- this.detoxIPCServer = detoxIPCServer;
48
- this.workerId = workerId;
49
- this.workersCount = workersCount;
50
- }
51
- }
52
-
53
- class PrimarySessionState extends SecondarySessionState {
54
- constructor({ contexts = [], failedTestFiles = [], logFiles = [], ...baseOpts }) {
55
- super(baseOpts);
56
-
57
- this.contexts = contexts;
58
- this.failedTestFiles = failedTestFiles;
59
- this.logFiles = logFiles;
60
- }
61
- }
62
-
63
- module.exports = {
64
- SessionState,
65
- PrimarySessionState,
66
- SecondarySessionState,
67
- };
62
+ module.exports = SessionState;
@@ -1,201 +1,330 @@
1
1
  const path = require('path');
2
- const { PassThrough } = require('stream');
3
2
 
4
- const bunyan = require('bunyan');
5
- const bunyanDebugStream = require('bunyan-debug-stream');
6
3
  const _ = require('lodash');
7
4
 
8
- const temporaryPath = require('../artifacts/utils/temporaryPath');
9
- const { DetoxInternalError } = require('../errors');
5
+ const { DetoxInternalError, DetoxError } = require('../errors');
10
6
  const { shortFormat } = require('../utils/dateUtils');
7
+ const isPromise = require('../utils/isPromise');
11
8
 
12
- const customConsoleLogger = require('./customConsoleLogger');
9
+ const BunyanLogger = require('./utils/BunyanLogger');
10
+ const CategoryThreadDispatcher = require('./utils/CategoryThreadDispatcher');
11
+ const MessageStack = require('./utils/MessageStack');
12
+ const customConsoleLogger = require('./utils/customConsoleLogger');
13
+ const sanitizeBunyanContext = require('./utils/sanitizeBunyanContext');
13
14
 
14
15
  /**
15
- * @typedef PrivateLoggerConfig
16
- * @property {string} [file]
16
+ * @typedef SharedLoggerConfig
17
+ * @property {string} file
18
+ * @property {Detox.DetoxLoggerConfig} [userConfig]
19
+ * @property {CategoryThreadDispatcher} [dispatcher]
20
+ * @property {BunyanLogger} [bunyan]
21
+ * @property {MessageStack} [messageStack]
17
22
  */
18
23
 
19
24
  class DetoxLogger {
20
25
  /**
21
- * @param {Detox.DetoxLoggerConfig & PrivateLoggerConfig} [config]
26
+ * @param {Pick<SharedLoggerConfig, 'file' | 'userConfig'>} sharedConfig
22
27
  * @param {object} [context]
23
- * @param {bunyan} [bunyanLogger]
24
28
  */
25
- constructor(config, context, bunyanLogger) {
26
- // IMPORTANT: all the loggers should share the same object instance of this._config
27
- this._config = config || {
28
- level: 'info',
29
- overrideConsole: 'none',
30
- options: {
31
- showDate: true,
32
- showLoggerName: true,
33
- showPid: true,
34
- showMetadata: false,
35
- },
36
- };
37
-
38
- if (config && !context) {
39
- this._config.file = temporaryPath.for.jsonl();
40
- }
29
+ constructor(sharedConfig, context) {
30
+ /**
31
+ * @type {SharedLoggerConfig}
32
+ * IMPORTANT: all instances of {@link DetoxLogger} must share the same object instance of this._sharedConfig.
33
+ */
34
+ this._sharedConfig = sharedConfig;
41
35
 
42
36
  /** @type {object | undefined} */
43
37
  this._context = context;
44
- /** @type {bunyan} */
45
- this._bunyan = bunyanLogger || this._initBunyanLogger();
46
-
47
- this.fatal = this._forward.bind(this, 'fatal');
48
- this.error = this._forward.bind(this, 'error');
49
- this.warn = this._forward.bind(this, 'warn');
50
- this.info = this._forward.bind(this, 'info');
51
- this.debug = this._forward.bind(this, 'debug');
52
- this.trace = this._forward.bind(this, 'trace');
53
38
 
54
- this.overrideConsole();
39
+ /** @public */
40
+ this.fatal = this._setupLogMethod('fatal');
41
+ /** @public */
42
+ this.error = this._setupLogMethod('error');
43
+ /** @public */
44
+ this.warn = this._setupLogMethod('warn');
45
+ /** @public */
46
+ this.info = this._setupLogMethod('info');
47
+ /** @public */
48
+ this.debug = this._setupLogMethod('debug');
49
+ /** @public */
50
+ this.trace = this._setupLogMethod('trace');
51
+
52
+ if (!context) {
53
+ // In this branch, `this` refers to the first (root) logger instance.
54
+
55
+ this._sharedConfig.userConfig = this._sharedConfig.userConfig || {
56
+ level: 'info',
57
+ overrideConsole: false,
58
+ options: {
59
+ showDate: false,
60
+ showLoggerName: false,
61
+ showProcess: false,
62
+ showPid: false,
63
+ showLevel: false,
64
+ showPrefixes: false,
65
+ showMetadata: false,
66
+ },
67
+ };
68
+
69
+ this._sharedConfig.bunyan = new BunyanLogger()
70
+ .installFileStream(this.file)
71
+ .installDebugStream(this.config);
72
+
73
+ this._sharedConfig.dispatcher = new CategoryThreadDispatcher();
74
+ this._sharedConfig.messageStack = new MessageStack();
75
+
76
+ this.overrideConsole();
77
+ }
55
78
  }
56
79
 
57
80
  /**
58
- * @internal
81
+ * @public
82
+ * @returns {Detox.DetoxLogLevel}
59
83
  */
60
- get config() {
61
- return this._config;
62
- }
63
-
64
- /** @returns {Detox.DetoxLogLevel} */
65
84
  get level() {
66
- return this._config.level;
85
+ return this.config.level;
67
86
  }
68
87
 
69
88
  /**
70
- * @internal
89
+ * @public
90
+ * @param {object} [overrides]
91
+ * @returns {DetoxLogger}
71
92
  */
93
+ child(overrides) {
94
+ const merged = this._mergeContexts(this._context, sanitizeBunyanContext(overrides));
95
+ return new DetoxLogger(this._sharedConfig, merged);
96
+ }
97
+
98
+ /** @internal */
99
+ get config() {
100
+ return this._sharedConfig.userConfig;
101
+ }
102
+
103
+ /** @internal */
72
104
  get file() {
73
- return this._config.file;
105
+ return this._sharedConfig.file;
74
106
  }
75
107
 
76
108
  /**
109
+ * @internal
77
110
  * @param config
78
111
  */
79
112
  async setConfig(config) {
80
- if (this._context !== undefined) {
81
- throw new DetoxInternalError('Trying to set a config for a non-root logger');
113
+ if (this._context) {
114
+ throw new DetoxInternalError('Trying to set a config in a non-root logger');
82
115
  }
83
116
 
84
- if (this.file) {
85
- throw new DetoxInternalError('Trying to set a config for a fully initialized logger');
86
- }
87
-
88
- _.merge(this._config, config);
89
-
90
- // @ts-ignore
91
- const [oldStream] = this._bunyan.streams.splice(0, 1);
92
- oldStream.stream.end();
93
- this._bunyan.addStream(this._createDebugStream());
117
+ _.merge(this.config, config);
118
+ this._sharedConfig.bunyan.installDebugStream(this.config);
119
+ this.overrideConsole();
120
+ }
94
121
 
95
- this._config.file = temporaryPath.for.jsonl();
96
- this._bunyan.addStream({
97
- level: 'trace',
98
- path: this._config.file,
99
- });
122
+ /**
123
+ * @internal
124
+ */
125
+ overrideConsole(sandbox) {
126
+ const enabled = this.config.overrideConsole;
127
+ if (!enabled) {
128
+ return;
129
+ }
100
130
 
101
- this.overrideConsole();
131
+ customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
102
132
  }
103
133
 
104
134
  /**
105
- * @param {object} [overrides]
106
- * @returns {DetoxLogger}
135
+ * @private
107
136
  */
108
- child(overrides) {
109
- if (overrides && overrides.__filename) {
110
- overrides.__filename = path.basename(overrides.__filename, '.js');
137
+ _mergeContexts(...contexts) {
138
+ const context = Object.assign({}, ...contexts);
139
+ const categories = _(contexts).flatMap((c) => {
140
+ if (c && c.cat) {
141
+ return _.isArray(c.cat) ? c.cat : c.cat.split(',');
142
+ }
143
+
144
+ return [];
145
+ }).uniq().join(',');
146
+
147
+ if (context.error || context.err) {
148
+ context.error = DetoxError.format(context.error || context.err);
149
+ delete context.err;
150
+ }
151
+
152
+ if (categories) {
153
+ context.cat = categories;
154
+ } else {
155
+ delete context.cat;
111
156
  }
112
157
 
113
- return new DetoxLogger(this._config, {
114
- ...this._context,
115
- ...overrides,
116
- }, this._bunyan);
158
+ if (context.__filename) {
159
+ context.__filename = path.basename(context.__filename);
160
+ }
161
+
162
+ context.ph = context.ph || 'i';
163
+ context.tid = this._sharedConfig.dispatcher.resolve(
164
+ context.ph,
165
+ context.cat,
166
+ context.id || 0
167
+ );
168
+
169
+ return context;
117
170
  }
118
171
 
119
172
  /**
120
- * @param {bunyan.LogLevel} level
121
- * @param {any[]} args
122
173
  * @private
174
+ * @param {Detox.DetoxLogLevel} level
175
+ * @returns {Detox._LogMethod}
123
176
  */
124
- _forward(level, ...args) {
125
- const msgContext = _.isError(args[0]) ? { err: args[0] } : _.isObject(args[0]) ? args[0] : undefined;
126
- const msgArgs = msgContext !== undefined ? args.slice(1) : args;
127
- const mergedContext = sanitizeBunyanContext({
128
- ...this._context,
129
- ...msgContext,
177
+ _setupLogMethod(level) {
178
+ const logMethod = this[level] = this._instant.bind(this, level);
179
+
180
+ return Object.assign(logMethod, {
181
+ begin: this._begin.bind(this, level),
182
+ complete: this._complete.bind(this, level),
183
+ end: this._end.bind(this, level),
130
184
  });
185
+ }
131
186
 
132
- this._bunyan[level](mergedContext, ...msgArgs);
187
+ /** @private */
188
+ _begin(level, ...args) {
189
+ const { context, msg } = this._parseArgs({ ph: 'B' }, args);
190
+ this._beginInternal(level, context, msg);
133
191
  }
134
192
 
135
- _initBunyanLogger() {
136
- /** @type {bunyan.Stream[]} */
137
- const streams = [this._createDebugStream()];
193
+ /** @private */
194
+ _beginInternal(level, context, msg) {
195
+ this._sharedConfig.messageStack.push(context.tid, msg);
196
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
197
+ }
138
198
 
139
- if (this._config.file) {
140
- streams.push({
141
- level: 'trace',
142
- path: this._config.file,
143
- });
199
+ /** @private */
200
+ _end(level, ...args) {
201
+ let { context, msg } = this._parseArgs({ ph: 'E' }, args);
202
+ this._endInternal(level, context, msg);
203
+ }
204
+
205
+ /** @private */
206
+ _endInternal(level, context, msg) {
207
+ const beginMsg = this._sharedConfig.messageStack.pop(context.tid);
208
+ if (msg.length === 0) {
209
+ msg = beginMsg;
144
210
  }
145
211
 
146
- return bunyan.createLogger({ name: 'detox', streams });
212
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
147
213
  }
148
214
 
149
- _createDebugStream() {
150
- const { out = process.stderr, ...streamOptions } = this._config.options;
151
- const passthrough = new PassThrough().pipe(out);
152
-
153
- return {
154
- type: 'raw',
155
- level: this._config.level,
156
- stream: bunyanDebugStream.default({
157
- ...streamOptions,
158
- out: passthrough,
159
- }),
160
- };
215
+ /**
216
+ * @private
217
+ * @param {import('bunyan').LogLevel} level
218
+ * @param {any[]} args
219
+ */
220
+ _instant(level, ...args) {
221
+ const { context, msg } = this._parseArgs(null, args);
222
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
161
223
  }
162
224
 
163
- overrideConsole(sandbox) {
164
- const option = this._config.overrideConsole;
165
- if (option === 'none') {
166
- return;
167
- }
225
+ /**
226
+ * @param {import('bunyan').LogLevel} level
227
+ * @private
228
+ */
229
+ _complete(level, maybeContext, maybeMessage, maybeAction) {
230
+ const action = typeof maybeContext !== 'string' ? maybeAction : maybeMessage;
231
+ const args = maybeAction === action ? [maybeContext, maybeMessage] : [maybeContext];
232
+ const { context, msg } = this._parseArgs(null, args);
233
+ const end = (ctx) => this[level].end({
234
+ id: context.id,
235
+ cat: context.cat,
236
+ ...ctx,
237
+ });
168
238
 
169
- if ((option === 'sandbox' && sandbox) || option === 'all') {
170
- customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
239
+ let result;
240
+ this._beginInternal(level, { ...context, ph: 'B' }, msg);
241
+ try {
242
+ result = typeof action === 'function'
243
+ ? action()
244
+ : action;
245
+
246
+ if (!isPromise(result)) {
247
+ end({ success: true });
248
+ } else {
249
+ result.then(
250
+ () => end({ success: true }),
251
+ (err) => end({ success: false, err }),
252
+ );
253
+ }
254
+
255
+ return result;
256
+ } catch (err) {
257
+ end({ success: false, err });
258
+ throw err;
171
259
  }
172
260
  }
173
261
 
174
- /** @type {bunyanDebugStream.BunyanDebugStreamOptions} */
175
- static defaultOptions = {
176
- showDate: shortFormat,
177
- showLoggerName: true,
178
- showPid: true,
179
- showMetadata: false,
180
- basepath: path.join(__dirname, '..'),
181
- prefixers: {
182
- '__filename': (filename, { entry }) => {
183
- if (entry.event === 'USER_LOG') {
184
- return '';
185
- }
186
-
187
- if (entry.event === 'ERROR') {
188
- return `${filename}/${entry.event}`;
189
- }
190
-
191
- return entry.event ? entry.event : filename;
192
- },
193
- 'trackingId': id => ` #${id}`,
194
- 'cpid': pid => ` cpid=${pid}`,
195
- },
196
- };
262
+ /** @private */
263
+ _parseArgs(boundContext, args) {
264
+ const userContext = _.isError(args[0])
265
+ ? { err: args[0] }
266
+ : _.isObject(args[0])
267
+ ? args[0]
268
+ : undefined;
269
+
270
+ const msg = userContext !== undefined ? args.slice(1) : args;
271
+
272
+ const context = this._mergeContexts(
273
+ this._context,
274
+ boundContext,
275
+ sanitizeBunyanContext(userContext),
276
+ );
277
+
278
+ return { context, msg };
279
+ }
280
+
281
+ /** @internal */
282
+ static defaultOptions({ level }) {
283
+ const ph = level === 'trace' || level === 'debug'
284
+ ? value => require('chalk').grey(value) + ' '
285
+ : value => require('chalk').grey(value);
286
+
287
+ const id = level === 'trace'
288
+ ? value => require('chalk').yellow(`@${value}`)
289
+ : undefined;
290
+
291
+ const cat = level === 'trace' || level === 'debug'
292
+ ? (value) => require('chalk').yellow(`${value}`.split(',', 1)[0])
293
+ : undefined;
294
+
295
+ const event = level === 'trace' || level === 'debug'
296
+ ? (value) => require('chalk').grey(`:${value}`)
297
+ : undefined;
298
+
299
+ const identity = x => x;
300
+
301
+ return ({
302
+ showDate: shortFormat,
303
+ showLoggerName: true,
304
+ showPid: true,
305
+ showLevel: false,
306
+ showMetadata: false,
307
+ showPrefixes: (p) => p.join(''),
308
+ basepath: path.join(__dirname, '..'),
309
+ prefixers: _.omitBy({
310
+ ph,
311
+ cat,
312
+ event,
313
+ id,
314
+ }, _.isUndefined),
315
+ stringifiers: _.omitBy({
316
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
317
+ 'args': args => `(${require('lodash').map(args, a => JSON.stringify(a)).join(', ')})`,
318
+ 'error': identity,
319
+ 'data': json => typeof json === 'string' ? json : JSON.stringify(json, null, 2),
320
+ 'stack': level === 'trace' || level === 'debug' ? identity : undefined,
321
+ 'origin': level === 'trace' || level === 'debug' ? identity : undefined,
322
+ }, _.isUndefined),
323
+ });
324
+ }
197
325
 
198
326
  /**
327
+ * @internal
199
328
  * @param {string} level
200
329
  * @returns {Detox.DetoxLogLevel}
201
330
  */
@@ -216,29 +345,4 @@ class DetoxLogger {
216
345
  }
217
346
  }
218
347
 
219
- const RESERVED_PROPERTIES = [
220
- 'hostname',
221
- 'level',
222
- 'msg',
223
- 'name',
224
- 'pid',
225
- 'time',
226
- ];
227
-
228
- function hasProperty(p) {
229
- return _.has(this, p);
230
- }
231
-
232
- function hasReservedProperties(o) {
233
- return RESERVED_PROPERTIES.some(hasProperty, o); // eslint-disable-line unicorn/no-array-method-this-argument
234
- }
235
-
236
- function escapeCallback(value, key) {
237
- return RESERVED_PROPERTIES.includes(key) ? `${key}$` : key;
238
- }
239
-
240
- function sanitizeBunyanContext(context) {
241
- return hasReservedProperties(context) ? _.mapKeys(context, escapeCallback) : context;
242
- }
243
-
244
348
  module.exports = DetoxLogger;
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ DetoxLogger: require('./DetoxLogger'),
3
+ DetoxLogFinalizer: require('./utils/DetoxLogFinalizer'),
4
+ installLegacyTracerInterface: require('./utils/tracerLegacy').install,
5
+ };