detox 20.0.4-breaking.new-global-lifecycle.0 → 20.0.7-prerelease.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar → 20.0.7-prerelease.0/detox-20.0.7-prerelease.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar → 20.0.7-prerelease.0/detox-20.0.7-prerelease.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom → 20.0.7-prerelease.0/detox-20.0.7-prerelease.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.7-prerelease.0/detox-20.0.7-prerelease.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/android/detox/proguard-rules-app.pro +4 -0
  29. package/android/detox/src/full/java/com/wix/detox/DetoxCrashHandler.kt +1 -1
  30. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  31. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +1 -1
  32. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
  33. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
  34. package/index.d.ts +58 -40
  35. package/internals.d.ts +63 -15
  36. package/local-cli/cli.js +1 -1
  37. package/local-cli/rebuild-framework-cache.js +1 -1
  38. package/local-cli/test.js +3 -2
  39. package/local-cli/test.test.js +1 -1
  40. package/local-cli/testCommand/TestRunnerCommand.js +10 -7
  41. package/package.json +5 -4
  42. package/runners/jest/globalSetup.js +1 -1
  43. package/runners/jest/globalTeardown.js +1 -1
  44. package/runners/jest/testEnvironment/index.js +36 -18
  45. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +76 -41
  46. package/runners/jest/testEnvironment/listeners/SpecReporter.js +1 -1
  47. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +1 -1
  48. package/src/DetoxWorker.js +4 -7
  49. package/src/android/core/NativeElement.js +56 -20
  50. package/src/android/core/NativeExpect.js +28 -9
  51. package/src/android/interactions/native.js +24 -18
  52. package/src/artifacts/ArtifactsManager.js +8 -23
  53. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  54. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  55. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  56. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  57. package/src/artifacts/templates/plugin/ArtifactPlugin.js +1 -1
  58. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  59. package/src/artifacts/utils/temporaryPath.js +18 -7
  60. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  61. package/src/client/AsyncWebSocket.js +8 -17
  62. package/src/client/Client.js +19 -2
  63. package/src/configuration/collectCliConfig.js +1 -1
  64. package/src/configuration/composeDeviceConfig.js +1 -1
  65. package/src/configuration/composeLoggerConfig.js +17 -8
  66. package/src/configuration/composeRunnerConfig.js +1 -1
  67. package/src/configuration/index.js +5 -1
  68. package/src/configuration/loadExternalConfig.js +1 -1
  69. package/src/devices/allocation/DeviceAllocator.js +3 -2
  70. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +1 -1
  71. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +3 -2
  72. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  73. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -2
  74. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  75. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +1 -1
  76. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  77. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  78. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  79. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  80. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  81. package/src/devices/common/drivers/android/tools/MonitoredInstrumentation.js +1 -1
  82. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +4 -2
  83. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +9 -13
  84. package/src/devices/runtime/RuntimeDevice.js +9 -12
  85. package/src/devices/runtime/drivers/DeviceDriverBase.js +1 -1
  86. package/src/devices/runtime/drivers/android/AndroidDriver.js +10 -2
  87. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +1 -1
  88. package/src/ios/expectTwo.js +152 -67
  89. package/src/ipc/IPCClient.js +3 -8
  90. package/src/ipc/IPCServer.js +11 -11
  91. package/src/ipc/{state.js → SessionState.js} +23 -50
  92. package/src/logger/DetoxLogger.js +268 -155
  93. package/src/logger/index.js +4 -0
  94. package/src/logger/utils/BunyanLogger.js +72 -0
  95. package/src/logger/utils/CategoryThreadDispatcher.js +58 -0
  96. package/src/logger/utils/MessageStack.js +24 -0
  97. package/src/logger/{TraceThreadDispatcher.js → utils/ThreadDispatcher.js} +34 -5
  98. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +4 -4
  99. package/src/logger/utils/sanitizeBunyanContext.js +28 -0
  100. package/src/logger/utils/tracerLegacy.js +48 -0
  101. package/src/realms/DetoxContext.js +65 -57
  102. package/src/realms/DetoxInternalsFacade.js +7 -5
  103. package/src/realms/DetoxPrimaryContext.js +125 -40
  104. package/src/realms/DetoxSecondaryContext.js +24 -29
  105. package/src/server/DetoxConnection.js +18 -23
  106. package/src/server/DetoxServer.js +7 -10
  107. package/src/server/DetoxSession.js +6 -6
  108. package/src/server/DetoxSessionManager.js +1 -1
  109. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  110. package/src/symbols.js +12 -8
  111. package/src/utils/childProcess/exec.js +1 -1
  112. package/src/utils/childProcess/spawn.js +1 -1
  113. package/src/utils/errorUtils.js +4 -3
  114. package/src/utils/invocationTraceDescriptions.js +43 -0
  115. package/src/utils/streamUtils.js +10 -11
  116. package/src/utils/trace.js +2 -18
  117. package/src/utils/traceMethods.js +15 -0
  118. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  119. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  120. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  121. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  122. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  123. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  124. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  125. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  126. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar +0 -0
  127. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.md5 +0 -1
  128. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha1 +0 -1
  129. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha256 +0 -1
  130. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha512 +0 -1
  131. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  132. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  133. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  134. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  135. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  136. package/src/logger/DetoxTracer.js +0 -133
  137. package/src/utils/ChromeTracingExporter.js +0 -54
@@ -3,6 +3,28 @@ const cycle = require('json-cycle');
3
3
  const uuid = require('../utils/uuid');
4
4
 
5
5
  class SessionState {
6
+ constructor({
7
+ id = uuid.UUID(),
8
+ contexts = [],
9
+ detoxConfigSnapshotPath = '',
10
+ detoxConfig = null,
11
+ detoxIPCServer = '',
12
+ failedTestFiles = [],
13
+ testFilesToRetry = [],
14
+ testSessionIndex = 0,
15
+ workersCount = 0
16
+ }) {
17
+ this.id = id;
18
+ this.contexts = contexts;
19
+ this.detoxConfigSnapshotPath = detoxConfigSnapshotPath;
20
+ this.detoxConfig = detoxConfig;
21
+ this.detoxIPCServer = detoxIPCServer;
22
+ this.failedTestFiles = failedTestFiles;
23
+ this.testFilesToRetry = testFilesToRetry;
24
+ this.testSessionIndex = testSessionIndex;
25
+ this.workersCount = workersCount;
26
+ }
27
+
6
28
  patch(state) {
7
29
  Object.assign(this, state);
8
30
  }
@@ -37,53 +59,4 @@ class SessionState {
37
59
  }
38
60
  }
39
61
 
40
- class SecondarySessionState extends SessionState {
41
- constructor({
42
- id = uuid.UUID(),
43
- detoxConfigSnapshotPath = '',
44
- detoxConfig = null,
45
- detoxIPCServer = '',
46
- failedTestFiles = [],
47
- testFilesToRetry = [],
48
- testSessionIndex = 0,
49
- workerId = undefined,
50
- workersCount = 0
51
- }) {
52
- super();
53
-
54
- this.id = id;
55
- this.detoxConfigSnapshotPath = detoxConfigSnapshotPath;
56
- this.detoxConfig = detoxConfig;
57
- this.detoxIPCServer = detoxIPCServer;
58
- this.failedTestFiles = failedTestFiles;
59
- this.testFilesToRetry = testFilesToRetry;
60
- this.testSessionIndex = testSessionIndex;
61
- this.workerId = workerId;
62
- this.workersCount = workersCount;
63
- }
64
- }
65
-
66
- class PrimarySessionState extends SecondarySessionState {
67
- constructor({
68
- contexts = [],
69
- logFiles = [],
70
- failedTestFiles = [],
71
- testFilesToRetry = [],
72
- testSessionIndex = 0,
73
- ...baseOpts
74
- }) {
75
- super(baseOpts);
76
-
77
- this.contexts = contexts;
78
- this.failedTestFiles = failedTestFiles;
79
- this.logFiles = logFiles;
80
- this.testSessionIndex = testSessionIndex;
81
- this.testFilesToRetry = testFilesToRetry;
82
- }
83
- }
84
-
85
- module.exports = {
86
- SessionState,
87
- PrimarySessionState,
88
- SecondarySessionState,
89
- };
62
+ module.exports = SessionState;
@@ -1,201 +1,339 @@
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
5
  const temporaryPath = require('../artifacts/utils/temporaryPath');
9
- const { DetoxInternalError } = require('../errors');
6
+ const { DetoxInternalError, DetoxError } = require('../errors');
10
7
  const { shortFormat } = require('../utils/dateUtils');
8
+ const isPromise = require('../utils/isPromise');
11
9
 
12
- const customConsoleLogger = require('./customConsoleLogger');
10
+ const BunyanLogger = require('./utils/BunyanLogger');
11
+ const CategoryThreadDispatcher = require('./utils/CategoryThreadDispatcher');
12
+ const MessageStack = require('./utils/MessageStack');
13
+ const customConsoleLogger = require('./utils/customConsoleLogger');
14
+ const sanitizeBunyanContext = require('./utils/sanitizeBunyanContext');
13
15
 
14
16
  /**
15
- * @typedef PrivateLoggerConfig
16
- * @property {string} [file]
17
+ * @typedef SharedLoggerConfig
18
+ * @property {string} file
19
+ * @property {Detox.DetoxLoggerConfig} userConfig
20
+ * @property {CategoryThreadDispatcher} [dispatcher]
21
+ * @property {BunyanLogger} [bunyan]
22
+ * @property {MessageStack} [messageStack]
17
23
  */
18
24
 
19
25
  class DetoxLogger {
20
26
  /**
21
- * @param {Detox.DetoxLoggerConfig & PrivateLoggerConfig} [config]
27
+ * @param {Pick<SharedLoggerConfig, 'file' | 'userConfig'>} sharedConfig
22
28
  * @param {object} [context]
23
- * @param {bunyan} [bunyanLogger]
24
29
  */
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
- }
30
+ constructor(sharedConfig, context) {
31
+ /**
32
+ * @type {SharedLoggerConfig}
33
+ * IMPORTANT: all instances of {@link DetoxLogger} must share the same object instance of this._sharedConfig.
34
+ */
35
+ this._sharedConfig = sharedConfig;
41
36
 
42
37
  /** @type {object | undefined} */
43
38
  this._context = context;
44
- /** @type {bunyan} */
45
- this._bunyan = bunyanLogger || this._initBunyanLogger();
46
39
 
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');
40
+ /** @public */
41
+ this.fatal = this._setupLogMethod('fatal');
42
+ /** @public */
43
+ this.error = this._setupLogMethod('error');
44
+ /** @public */
45
+ this.warn = this._setupLogMethod('warn');
46
+ /** @public */
47
+ this.info = this._setupLogMethod('info');
48
+ /** @public */
49
+ this.debug = this._setupLogMethod('debug');
50
+ /** @public */
51
+ this.trace = this._setupLogMethod('trace');
52
+
53
+ if (!context) {
54
+ // In this branch, `this` refers to the first (root) logger instance.
55
+
56
+ this._sharedConfig.userConfig = this._sharedConfig.userConfig || {
57
+ level: 'info',
58
+ overrideConsole: 'none',
59
+ options: {
60
+ showDate: true,
61
+ showLoggerName: true,
62
+ showPid: true,
63
+ showPrefixes: false,
64
+ showMetadata: false,
65
+ },
66
+ };
67
+
68
+ this._sharedConfig.bunyan = new BunyanLogger()
69
+ .installFileStream(this.file)
70
+ .installDebugStream(this.config);
71
+
72
+ this._sharedConfig.dispatcher = new CategoryThreadDispatcher({
73
+ logger: this,
74
+ categories: {
75
+ 'lifecycle': [0],
76
+ 'cli': [1],
77
+ 'logger': [2],
78
+ 'ipc': [29],
79
+ 'ws-server': [50, 99],
80
+ 'ws-client': [100, 149],
81
+ 'device': [150, 159],
82
+ 'artifacts-manager': [300],
83
+ 'artifacts-plugin': [310, 349],
84
+ 'artifact': [350, 399],
85
+ 'child-process': [400, 499],
86
+ 'default': [999],
87
+ 'user': [10000, 10999]
88
+ },
89
+ });
53
90
 
54
- this.overrideConsole();
91
+ this._sharedConfig.messageStack = new MessageStack();
92
+
93
+ this.overrideConsole();
94
+ }
55
95
  }
56
96
 
57
97
  /**
58
- * @internal
98
+ * @public
99
+ * @returns {Detox.DetoxLogLevel}
59
100
  */
60
- get config() {
61
- return this._config;
62
- }
63
-
64
- /** @returns {Detox.DetoxLogLevel} */
65
101
  get level() {
66
- return this._config.level;
102
+ return this.config.level;
67
103
  }
68
104
 
69
105
  /**
70
- * @internal
106
+ * @public
107
+ * @param {object} [overrides]
108
+ * @returns {DetoxLogger}
71
109
  */
110
+ child(overrides) {
111
+ const merged = this._mergeContexts(this._context, overrides);
112
+ return new DetoxLogger(this._sharedConfig, merged);
113
+ }
114
+
115
+ /** @internal */
116
+ get config() {
117
+ return this._sharedConfig.userConfig;
118
+ }
119
+
120
+ /** @internal */
72
121
  get file() {
73
- return this._config.file;
122
+ return this._sharedConfig.file;
74
123
  }
75
124
 
76
125
  /**
126
+ * @internal
77
127
  * @param config
78
128
  */
79
129
  async setConfig(config) {
80
- if (this._context !== undefined) {
81
- throw new DetoxInternalError('Trying to set a config for a non-root logger');
130
+ if (this._context) {
131
+ throw new DetoxInternalError('Trying to set a config in a non-root logger');
82
132
  }
83
133
 
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());
134
+ _.merge(this.config, config);
135
+ this._sharedConfig.file = temporaryPath.for.jsonl();
136
+ this._sharedConfig.bunyan.installDebugStream(this.config);
137
+ this.overrideConsole();
138
+ }
94
139
 
95
- this._config.file = temporaryPath.for.jsonl();
96
- this._bunyan.addStream({
97
- level: 'trace',
98
- path: this._config.file,
99
- });
140
+ /**
141
+ * @internal
142
+ */
143
+ overrideConsole(sandbox) {
144
+ const option = this.config.overrideConsole;
145
+ if (option === 'none') {
146
+ return;
147
+ }
100
148
 
101
- this.overrideConsole();
149
+ if ((option === 'sandbox' && sandbox) || option === 'all') {
150
+ customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
151
+ }
102
152
  }
103
153
 
104
154
  /**
105
- * @param {object} [overrides]
106
- * @returns {DetoxLogger}
155
+ * @private
107
156
  */
108
- child(overrides) {
109
- if (overrides && overrides.__filename) {
110
- overrides.__filename = path.basename(overrides.__filename, '.js');
157
+ _mergeContexts(...contexts) {
158
+ const context = Object.assign({}, ...contexts);
159
+
160
+ if (context.error || context.err) {
161
+ context.error = DetoxError.format(context.error || context.err);
162
+ delete context.err;
163
+ }
164
+
165
+ if (Array.isArray(context.cat)) {
166
+ context.cat = context.cat.join(',');
111
167
  }
112
168
 
113
- return new DetoxLogger(this._config, {
114
- ...this._context,
115
- ...overrides,
116
- }, this._bunyan);
169
+ if (context.__filename) {
170
+ context.__filename = path.basename(context.__filename);
171
+ }
172
+
173
+ context.ph = context.ph || 'i';
174
+ context.cat = context.cat || '';
175
+
176
+ context.tid = this._sharedConfig.dispatcher.resolve(
177
+ context.ph,
178
+ context.cat,
179
+ context.id || 0
180
+ );
181
+
182
+ return sanitizeBunyanContext(context);
117
183
  }
118
184
 
119
185
  /**
120
- * @param {bunyan.LogLevel} level
121
- * @param {any[]} args
122
186
  * @private
187
+ * @param {Detox.DetoxLogLevel} level
188
+ * @returns {Detox._LogMethod}
123
189
  */
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,
130
- });
190
+ _setupLogMethod(level) {
191
+ const logMethod = this[level] = this._instant.bind(this, level);
131
192
 
132
- this._bunyan[level](mergedContext, ...msgArgs);
193
+ return Object.assign(logMethod, {
194
+ begin: this._begin.bind(this, level),
195
+ complete: this._complete.bind(this, level),
196
+ end: this._end.bind(this, level),
197
+ });
133
198
  }
134
199
 
135
- _initBunyanLogger() {
136
- /** @type {bunyan.Stream[]} */
137
- const streams = [this._createDebugStream()];
200
+ /** @private */
201
+ _begin(level, ...args) {
202
+ const { context, msg } = this._parseArgs({ ph: 'B' }, args);
203
+ this._sharedConfig.messageStack.push(context.tid, msg);
204
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
205
+ }
138
206
 
139
- if (this._config.file) {
140
- streams.push({
141
- level: 'trace',
142
- path: this._config.file,
143
- });
207
+ /** @private */
208
+ _end(level, ...args) {
209
+ let { context, msg } = this._parseArgs({ ph: 'E' }, args);
210
+ if (msg.length === 0) {
211
+ msg = this._sharedConfig.messageStack.pop(context.tid);
144
212
  }
145
213
 
146
- return bunyan.createLogger({ name: 'detox', streams });
214
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
147
215
  }
148
216
 
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
- };
217
+ /**
218
+ * @private
219
+ * @param {import('bunyan').LogLevel} level
220
+ * @param {any[]} args
221
+ */
222
+ _instant(level, ...args) {
223
+ const { context, msg } = this._parseArgs(null, args);
224
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
161
225
  }
162
226
 
163
- overrideConsole(sandbox) {
164
- const option = this._config.overrideConsole;
165
- if (option === 'none') {
166
- return;
227
+ /**
228
+ * @param {import('bunyan').LogLevel} level
229
+ * @private
230
+ */
231
+ _complete(level, maybeContext, maybeMessage, maybeAction) {
232
+ const action = typeof maybeContext !== 'string' ? maybeAction : maybeMessage;
233
+ const args = maybeAction === action ? [maybeContext, maybeMessage] : [maybeContext];
234
+ const { context, msg } = this._parseArgs(null, args);
235
+ const end = (ctx) => this[level].end({
236
+ id: context.id,
237
+ cat: context.cat,
238
+ ...ctx,
239
+ });
240
+
241
+ let result;
242
+ this[level].begin(context, ...msg);
243
+ try {
244
+ result = typeof action === 'function'
245
+ ? action()
246
+ : action;
247
+
248
+ if (!isPromise(result)) {
249
+ end(context);
250
+ } else {
251
+ result.then(
252
+ () => end({ success: true }),
253
+ (err) => end({ success: false, err }),
254
+ );
255
+ }
256
+
257
+ return result;
258
+ } catch (err) {
259
+ end({ success: false, err });
260
+ throw err;
167
261
  }
262
+ }
168
263
 
169
- if ((option === 'sandbox' && sandbox) || option === 'all') {
170
- customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
264
+ /** @private */
265
+ _parseArgs(boundContext, args) {
266
+ const userContext = _.isError(args[0])
267
+ ? { err: args[0] }
268
+ : _.isObject(args[0])
269
+ ? args[0]
270
+ : undefined;
271
+ const msg = userContext !== undefined ? args.slice(1) : args;
272
+
273
+ if (userContext) {
274
+ delete userContext.pid;
275
+ delete userContext.tid;
276
+ delete userContext.ts;
277
+ delete userContext.time;
278
+ delete userContext.ph;
171
279
  }
280
+
281
+ const context = this._mergeContexts(
282
+ this._context,
283
+ boundContext,
284
+ userContext,
285
+ );
286
+
287
+ return { context, msg };
172
288
  }
173
289
 
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
- };
290
+ /** @internal */
291
+ static defaultOptions({ level }) {
292
+ const ph = level === 'trace' || level === 'debug'
293
+ ? value => require('chalk').grey(value) + ' '
294
+ : value => require('chalk').grey(value);
295
+
296
+ const id = level === 'trace'
297
+ ? value => require('chalk').yellow(`@${value}`)
298
+ : undefined;
299
+
300
+ const cat = level === 'trace' || level === 'debug'
301
+ ? (value) => require('chalk').yellow((value || '').split(',', 1)[0])
302
+ : undefined;
303
+
304
+ const event = level === 'trace' || level === 'debug'
305
+ ? (value) => require('chalk').grey(`:${value}`)
306
+ : undefined;
307
+
308
+ const identity = x => x;
309
+
310
+ return ({
311
+ showDate: shortFormat,
312
+ showLoggerName: true,
313
+ showPid: true,
314
+ showLevel: false,
315
+ showMetadata: false,
316
+ showPrefixes: (p) => p.join(''),
317
+ basepath: path.join(__dirname, '..'),
318
+ prefixers: _.omitBy({
319
+ ph,
320
+ cat,
321
+ event,
322
+ id,
323
+ }, _.isUndefined),
324
+ stringifiers: _.omitBy({
325
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
326
+ 'args': args => `(${require('lodash').map(args, a => JSON.stringify(a)).join(', ')})`,
327
+ 'error': identity,
328
+ 'data': json => typeof json === 'string' ? json : JSON.stringify(json, null, 2),
329
+ 'stack': level === 'trace' || level === 'debug' ? identity : undefined,
330
+ 'origin': level === 'trace' || level === 'debug' ? identity : undefined,
331
+ }, _.isUndefined),
332
+ });
333
+ }
197
334
 
198
335
  /**
336
+ * @internal
199
337
  * @param {string} level
200
338
  * @returns {Detox.DetoxLogLevel}
201
339
  */
@@ -216,29 +354,4 @@ class DetoxLogger {
216
354
  }
217
355
  }
218
356
 
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
357
  module.exports = DetoxLogger;
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ DetoxLogger: require('./DetoxLogger'),
3
+ installLegacyTracerInterface: require('./utils/tracerLegacy').install,
4
+ };
@@ -0,0 +1,72 @@
1
+ const { PassThrough } = require('stream');
2
+
3
+ const bunyan = require('bunyan');
4
+ const bds = require('bunyan-debug-stream');
5
+ const _ = require('lodash');
6
+
7
+ const { DetoxInternalError } = require('../../errors');
8
+
9
+ class BunyanLogger {
10
+ constructor() {
11
+ this._bunyan = bunyan.createLogger({ name: 'detox', streams: [] });
12
+ /** @type {bunyan.Stream} */
13
+ this._debugStream = null;
14
+ /** @type {bunyan.Stream} */
15
+ this._fileStream = null;
16
+ }
17
+
18
+ /**
19
+ * @returns {bunyan}
20
+ */
21
+ get logger() {
22
+ return this._bunyan;
23
+ }
24
+
25
+ /**
26
+ * @param {Detox.DetoxLoggerConfig} config
27
+ * @returns {this}
28
+ */
29
+ installDebugStream(config) {
30
+ const level = config.level || 'info';
31
+
32
+ if (this._debugStream) {
33
+ _.remove(this._bunyan['streams'], this._debugStream);
34
+ // @ts-ignore
35
+ this._debugStream.stream.end();
36
+ this._debugStream = null;
37
+ }
38
+
39
+ this._debugStream = {
40
+ type: 'raw',
41
+ level,
42
+ stream: bds.default({
43
+ ...config.options,
44
+ out: new PassThrough().pipe(process.stderr),
45
+ }),
46
+ };
47
+
48
+ this._bunyan.addStream(this._debugStream);
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * @param {string} file
54
+ * @returns {this}
55
+ */
56
+ installFileStream(file) {
57
+ if (this._fileStream) {
58
+ throw new DetoxInternalError('Trying to install a second file stream inside already initialized Bunyan logger');
59
+ }
60
+
61
+ this._fileStream = {
62
+ level: 'trace',
63
+ path: file,
64
+ };
65
+
66
+ this._bunyan.addStream(this._fileStream);
67
+
68
+ return this;
69
+ }
70
+ }
71
+
72
+ module.exports = BunyanLogger;