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
@@ -1,24 +1,34 @@
1
1
  const path = require('path');
2
2
  const { URL } = require('url');
3
+ const { promisify } = require('util');
3
4
 
4
5
  const fs = require('fs-extra');
6
+ const glob = require('glob');
5
7
  const pipe = require('multipipe');
8
+ const onSignalExit = require('signal-exit');
6
9
 
7
10
  const temporary = require('../artifacts/utils/temporaryPath');
8
11
  const { DetoxRuntimeError } = require('../errors');
9
- const { PrimarySessionState } = require('../ipc/state');
12
+ const SessionState = require('../ipc/SessionState');
10
13
  const symbols = require('../symbols');
11
14
 
15
+ const globAsync = promisify(glob);
16
+ const globSync = glob.sync;
17
+
12
18
  const DetoxContext = require('./DetoxContext');
13
19
 
14
- const { $logger, $restoreSessionState, $sessionState } = DetoxContext.protected;
20
+ const { $restoreSessionState, $sessionState, $worker } = DetoxContext.protected;
15
21
 
16
22
  const _finalizeLogs = Symbol('finalizeLogs');
23
+ const _finalizeLogsSync = Symbol('finalizeLogsSync');
17
24
  const _globalLifecycleHandler = Symbol('globalLifecycleHandler');
18
25
  const _ipcServer = Symbol('ipcServer');
19
26
  const _resetLockFile = Symbol('resetLockFile');
20
27
  const _wss = Symbol('wss');
21
28
  const _dirty = Symbol('dirty');
29
+ const _emergencyTeardown = Symbol('emergencyTeardown');
30
+ const _areLogsEnabled = Symbol('areLogsEnabled');
31
+ const _lifecycleLogger = Symbol('lifecycleLogger');
22
32
 
23
33
  class DetoxPrimaryContext extends DetoxContext {
24
34
  constructor() {
@@ -31,6 +41,8 @@ class DetoxPrimaryContext extends DetoxContext {
31
41
  * @type {import('../ipc/IPCServer') | null}
32
42
  */
33
43
  this[_ipcServer] = null;
44
+ /** @type {Detox.Logger} */
45
+ this[_lifecycleLogger] = this[symbols.logger].child({ cat: 'lifecycle' });
34
46
  }
35
47
 
36
48
  //#region Internal members
@@ -41,7 +53,7 @@ class DetoxPrimaryContext extends DetoxContext {
41
53
  }
42
54
 
43
55
  async [symbols.resolveConfig](opts = {}) {
44
- const session = this[symbols.session];
56
+ const session = this[$sessionState];
45
57
  if (!session.detoxConfig) {
46
58
  const configuration = require('../configuration');
47
59
  session.detoxConfig = await configuration.composeDetoxConfig(opts);
@@ -52,9 +64,9 @@ class DetoxPrimaryContext extends DetoxContext {
52
64
 
53
65
  /**
54
66
  * @override
55
- * @param {Partial<DetoxInternals.DetoxGlobalSetupOptions>} [opts]
67
+ * @param {Partial<DetoxInternals.DetoxInitOptions>} [opts]
56
68
  */
57
- async [symbols.globalSetup](opts) {
69
+ async [symbols.init](opts = {}) {
58
70
  if (this[_dirty]) {
59
71
  throw new DetoxRuntimeError({
60
72
  message: 'Cannot initialize primary Detox context more than once.',
@@ -63,6 +75,8 @@ class DetoxPrimaryContext extends DetoxContext {
63
75
  }
64
76
 
65
77
  this[_dirty] = true;
78
+ onSignalExit(this[_emergencyTeardown]);
79
+
66
80
  const detoxConfig = await this[symbols.resolveConfig](opts);
67
81
 
68
82
  const {
@@ -71,18 +85,16 @@ class DetoxPrimaryContext extends DetoxContext {
71
85
  logger: loggerConfig,
72
86
  session: sessionConfig
73
87
  } = detoxConfig;
74
- await this[$logger].setConfig(loggerConfig);
88
+ await this[symbols.logger].setConfig(loggerConfig);
75
89
 
76
- this.trace.begin({
77
- cat: 'lifecycle',
78
- args: this[$sessionState],
79
- name: process.argv.slice(1).join(' '),
80
- });
90
+ this[_lifecycleLogger].trace.begin({
91
+ data: this[$sessionState],
92
+ }, process.argv.slice(1).join(' '));
81
93
 
82
94
  const IPCServer = require('../ipc/IPCServer');
83
95
  this[_ipcServer] = new IPCServer({
84
96
  sessionState: this[$sessionState],
85
- logger: this[$logger],
97
+ logger: this[symbols.logger],
86
98
  });
87
99
 
88
100
  await this[_ipcServer].init();
@@ -111,63 +123,98 @@ class DetoxPrimaryContext extends DetoxContext {
111
123
  }
112
124
 
113
125
  if (!sessionConfig.server && this[_wss]) {
126
+ // @ts-ignore
114
127
  sessionConfig.server = `ws://localhost:${this[_wss].port}`;
115
128
  }
116
129
 
117
130
  await fs.writeFile(this[$sessionState].detoxConfigSnapshotPath, this[$sessionState].stringify());
118
131
  process.env.DETOX_CONFIG_SNAPSHOT_PATH = this[$sessionState].detoxConfigSnapshotPath;
119
132
 
120
- // TODO: think about signal-exit and cleaning up the logs
133
+ if (opts.workerId !== null) {
134
+ await this[symbols.installWorker](opts);
135
+ }
121
136
  }
122
137
 
123
138
  /**
124
139
  * @override
125
- * @param {Partial<DetoxInternals.DetoxConfigurationSetupOptions>} [opts]
140
+ * @param {Partial<DetoxInternals.DetoxInstallWorkerOptions>} [opts]
126
141
  */
127
- async [symbols.setup](opts = {}) {
128
- const workerId = opts.workerId || 1;
129
- this[$sessionState].workerId = workerId;
142
+ async [symbols.installWorker](opts = {}) {
143
+ const workerId = this[$sessionState].workerId = opts.workerId = opts.workerId || 'worker';
130
144
  this[_ipcServer].onRegisterWorker({ workerId });
131
- await super[symbols.setup](opts);
145
+
146
+ await super[symbols.installWorker](opts);
132
147
  }
133
148
 
134
149
  /** @override */
135
- async [symbols.globalTeardown]() {
150
+ async [symbols.cleanup]() {
151
+ try {
152
+ if (this[$worker]) {
153
+ await this[symbols.uninstallWorker]();
154
+ }
155
+ } finally {
156
+ if (this[_globalLifecycleHandler]) {
157
+ await this[_globalLifecycleHandler].globalCleanup();
158
+ this[_globalLifecycleHandler] = null;
159
+ }
160
+
161
+ if (this[_wss]) {
162
+ await this[_wss].close();
163
+ this[_wss] = null;
164
+ }
165
+
166
+ if (this[_ipcServer]) {
167
+ await this[_ipcServer].dispose();
168
+ this[_ipcServer] = null;
169
+ }
170
+
171
+ await fs.remove(this[$sessionState].detoxConfigSnapshotPath);
172
+
173
+ try {
174
+ this[_lifecycleLogger].trace.end();
175
+ await this[_finalizeLogs]();
176
+ } catch (err) {
177
+ this[_lifecycleLogger].error({ err }, 'Encountered an error while merging the process logs:');
178
+ }
179
+ }
180
+ }
181
+
182
+ [_emergencyTeardown] = (_code, signal) => {
183
+ if (!signal) {
184
+ return;
185
+ }
186
+
136
187
  if (this[_globalLifecycleHandler]) {
137
- await this[_globalLifecycleHandler].globalCleanup();
188
+ this[_globalLifecycleHandler].emergencyCleanup();
138
189
  this[_globalLifecycleHandler] = null;
139
190
  }
140
191
 
141
192
  if (this[_wss]) {
142
- await this[_wss].close();
143
- this[_wss] = null;
193
+ this[_wss].close();
144
194
  }
145
195
 
146
196
  if (this[_ipcServer]) {
147
- await this[_ipcServer].dispose();
148
- this[_ipcServer] = null;
197
+ this[_ipcServer].dispose();
149
198
  }
150
199
 
151
- await fs.remove(this[$sessionState].detoxConfigSnapshotPath);
152
- delete process.env.DETOX_CONFIG_SNAPSHOT_PATH;
153
-
154
200
  try {
155
- this.trace.end({ cat: 'lifecycle' });
156
- await this[_finalizeLogs]();
201
+ this[_lifecycleLogger].trace.end({ abortSignal: signal });
202
+ this[_finalizeLogsSync]();
157
203
  } catch (err) {
158
- this[$logger].error({ err }, 'Encountered an error while merging the process logs:');
204
+ this[symbols.logger].error({ err }, 'Encountered an error while merging the process logs:');
159
205
  }
160
- }
206
+ };
207
+
161
208
  //#endregion
162
209
 
163
210
  //#region Protected members
164
211
  /**
165
212
  * @protected
166
213
  * @override
167
- * @return {PrimarySessionState}
214
+ * @return {SessionState}
168
215
  */
169
216
  [$restoreSessionState]() {
170
- return new PrimarySessionState({
217
+ return new SessionState({
171
218
  detoxConfigSnapshotPath: temporary.for.json(),
172
219
  detoxIPCServer: `primary-${process.pid}`,
173
220
  });
@@ -176,17 +223,16 @@ class DetoxPrimaryContext extends DetoxContext {
176
223
 
177
224
  //#region Private members
178
225
  async[_finalizeLogs]() {
179
- const logs = [this[$logger].file, ...this[$sessionState].logFiles].filter(f => f && fs.existsSync(f));
226
+ const sessionId = this[$sessionState].id;
227
+ const logs = await globAsync(temporary.for.jsonl(`${sessionId}.*`));
180
228
  if (logs.length === 0) {
181
229
  return;
182
230
  }
183
231
 
184
- const streamUtils = require('../utils/streamUtils');
185
- const { rootDir, plugins } = this[symbols.config].artifacts || {};
186
- const logConfig = plugins && plugins.log || 'none';
187
- const enabled = rootDir && (typeof logConfig === 'string' ? logConfig !== 'none' : logConfig.enabled);
232
+ if (this[_areLogsEnabled]()) {
233
+ const streamUtils = require('../utils/streamUtils');
234
+ const { rootDir } = this[symbols.config].artifacts;
188
235
 
189
- if (enabled) {
190
236
  await fs.mkdirp(rootDir);
191
237
  const [out1Stream, out2Stream, out3Stream] = ['detox.log.jsonl', 'detox.log', 'detox.trace.json']
192
238
  .map((filename) => fs.createWriteStream(path.join(rootDir, filename)));
@@ -198,7 +244,7 @@ class DetoxPrimaryContext extends DetoxContext {
198
244
 
199
245
  await Promise.all([
200
246
  pipe(mergedStream, streamUtils.writeJSONL(), out1Stream),
201
- pipe(mergedStream, streamUtils.debugStream(this[$logger].config.options), out2Stream),
247
+ pipe(mergedStream, streamUtils.debugStream(this[symbols.logger].config.options), out2Stream),
202
248
  pipe(mergedStream, streamUtils.chromeTraceStream(), streamUtils.writeJSON(), out3Stream),
203
249
  ]);
204
250
  }
@@ -206,6 +252,45 @@ class DetoxPrimaryContext extends DetoxContext {
206
252
  await Promise.all(logs.map(filepath => fs.remove(filepath)));
207
253
  }
208
254
 
255
+ async[_finalizeLogsSync]() {
256
+ const logsEnabled = this[_areLogsEnabled]();
257
+
258
+ const { rootDir } = this[symbols.config].artifacts;
259
+
260
+ if (logsEnabled) {
261
+ fs.mkdirpSync(rootDir);
262
+ }
263
+
264
+ const sessionId = this[$sessionState].id;
265
+ const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
266
+
267
+ for (const log of logs) {
268
+ if (logsEnabled) {
269
+ fs.moveSync(log, path.join(rootDir, path.basename(log)));
270
+ } else {
271
+ fs.removeSync(log);
272
+ }
273
+ }
274
+ }
275
+
276
+ [_areLogsEnabled]() {
277
+ const { rootDir, plugins } = this[symbols.config].artifacts || {};
278
+ if (!rootDir || !plugins) {
279
+ return false;
280
+ }
281
+
282
+ if (!plugins.log.enabled) {
283
+ return false;
284
+ }
285
+
286
+ if (!plugins.log.keepOnlyFailedTestsArtifacts) {
287
+ return true;
288
+ }
289
+
290
+ const { failedTestFiles, testFilesToRetry } = this[$sessionState];
291
+ return failedTestFiles.length + testFilesToRetry.length > 0;
292
+ }
293
+
209
294
  async[_resetLockFile]() {
210
295
  const DeviceRegistry = require('../devices/DeviceRegistry');
211
296
 
@@ -1,12 +1,12 @@
1
1
  const fs = require('fs');
2
2
 
3
3
  const { DetoxInternalError } = require('../errors');
4
- const { SecondarySessionState } = require('../ipc/state');
4
+ const SessionState = require('../ipc/SessionState');
5
5
  const symbols = require('../symbols');
6
6
 
7
7
  const DetoxContext = require('./DetoxContext');
8
8
 
9
- const { $logger, $restoreSessionState, $sessionState } = DetoxContext.protected;
9
+ const { $restoreSessionState, $sessionState, $worker } = DetoxContext.protected;
10
10
  const _ipcClient = Symbol('ipcClient');
11
11
  const _shortLifecycle = Symbol('shortLifecycle');
12
12
 
@@ -22,6 +22,8 @@ class DetoxSecondaryContext extends DetoxContext {
22
22
  /**
23
23
  * @private
24
24
  * @type {undefined | boolean}
25
+ *
26
+ * TODO: explain what is short lifecycle and why we need it
25
27
  */
26
28
  this[_shortLifecycle] = false;
27
29
  }
@@ -40,59 +42,52 @@ class DetoxSecondaryContext extends DetoxContext {
40
42
  }
41
43
 
42
44
  /** @override */
43
- async [symbols.globalSetup]() {
45
+ async [symbols.init](opts = {}) {
44
46
  const IPCClient = require('../ipc/IPCClient');
45
47
 
46
48
  this[_ipcClient] = new IPCClient({
47
49
  id: `secondary-${process.pid}`,
48
50
  state: this[$sessionState],
49
- logger: this[$logger],
51
+ logger: this[symbols.logger],
50
52
  });
51
53
 
52
54
  await this[_ipcClient].init();
53
- }
54
55
 
55
- /** @override */
56
- async [symbols.globalTeardown]() {
57
- if (this[_ipcClient]) {
58
- await this[_ipcClient].dispose();
59
- this[_ipcClient] = null;
56
+ if (opts.workerId !== null) {
57
+ await this[symbols.installWorker](opts);
60
58
  }
61
59
  }
62
60
 
63
61
  /** @override */
64
- async [symbols.setup](opts = {}) {
65
- if (!this[_ipcClient]) {
66
- this[_shortLifecycle] = true;
67
- await this[symbols.globalSetup]();
68
- }
69
-
70
- const workerId = opts.workerId || 1;
71
- await this[_ipcClient].registerWorker(workerId);
72
- await super[symbols.setup](opts);
73
- }
74
-
75
- /** @override */
76
- async [symbols.teardown]() {
62
+ async [symbols.cleanup]() {
77
63
  try {
78
- await super[symbols.teardown]();
64
+ if (this[$worker]) {
65
+ await this[symbols.uninstallWorker]();
66
+ }
79
67
  } finally {
80
- if (this[_shortLifecycle]) {
81
- await this[symbols.globalTeardown]();
68
+ if (this[_ipcClient]) {
69
+ await this[_ipcClient].dispose();
70
+ this[_ipcClient] = null;
82
71
  }
83
72
  }
84
73
  }
74
+
75
+ /** @override */
76
+ async [symbols.installWorker](opts = {}) {
77
+ const workerId = opts.workerId = opts.workerId || 'worker';
78
+ await this[_ipcClient].registerWorker(workerId);
79
+ await super[symbols.installWorker](opts);
80
+ }
85
81
  //#endregion
86
82
 
87
83
  //#region Protected members
88
-
89
84
  /**
90
85
  * @protected
91
86
  * @override
92
- * @return {SecondarySessionState}
87
+ * @return {SessionState}
93
88
  */
94
89
  [$restoreSessionState]() {
95
- return SecondarySessionState.parse(fs.readFileSync(process.env.DETOX_CONFIG_SNAPSHOT_PATH));
90
+ return SessionState.parse(fs.readFileSync(process.env.DETOX_CONFIG_SNAPSHOT_PATH));
96
91
  }
97
92
  //#endregion
98
93
  }
@@ -1,43 +1,37 @@
1
- // @ts-nocheck
2
1
  const _ = require('lodash');
3
- const { WebSocket } = require('ws'); // eslint-disable-line @typescript-eslint/no-unused-vars, no-unused-vars
4
2
 
5
3
  const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
6
- const logger = require('../utils/logger').child({ __filename, cat: 'ws-server,ws' });
4
+ const logger = require('../utils/logger').child({ cat: 'ws-server,ws' });
7
5
 
8
6
  const AnonymousConnectionHandler = require('./handlers/AnonymousConnectionHandler');
9
7
 
10
- const EVENTS = {
11
- NEW: { event: 'WSS_CONNECTION' },
12
- GET: { event: 'WSS_GET_FROM' },
13
- SEND: { event: 'WSS_SEND_TO' },
14
- ERROR: { event: 'ERROR' },
15
- SOCKET_ERROR: { event: 'WSS_SOCKET_ERROR' },
16
- };
17
-
18
8
  class DetoxConnection {
19
9
  /**
20
- * @param {DetoxSessionManager} sessionManager
21
- * @param {WebSocket} webSocket
22
- * @param {Socket} socket
10
+ * @param {{
11
+ * sessionManager: import('./DetoxSessionManager');
12
+ * webSocket: import('ws');
13
+ * socket: import('net').Socket;
14
+ * }} config
23
15
  */
24
16
  constructor({ sessionManager, webSocket, socket }) {
25
17
  this._onMessage = this._onMessage.bind(this);
26
18
  this._onError = this._onError.bind(this);
27
19
  this._onClose = this._onClose.bind(this);
28
20
 
29
- this._log = logger.child({ trackingId: socket.remotePort });
21
+ this._log = logger.child({ id: socket.remotePort });
22
+ this._log.debug.begin(`connection :${socket.localPort}<->:${socket.remotePort}`);
23
+
30
24
  this._sessionManager = sessionManager;
31
25
  this._webSocket = webSocket;
32
26
  this._webSocket.on('message', this._onMessage);
33
27
  this._webSocket.on('error', this._onError);
34
28
  this._webSocket.on('close', this._onClose);
35
- this._log.debug(EVENTS.NEW, 'registered a new connection.');
36
29
 
37
- const log = this._log;
30
+ // eslint-disable-next-line unicorn/no-this-assignment
31
+ const self = this;
38
32
  this._handler = new AnonymousConnectionHandler({
39
33
  api: {
40
- get log() { return log; },
34
+ get log() { return self._log; },
41
35
  appendLogDetails: (details) => { this._log = this._log.child(details); },
42
36
 
43
37
  registerSession: (params) => this._sessionManager.registerSession(this, params),
@@ -49,13 +43,13 @@ class DetoxConnection {
49
43
 
50
44
  sendAction(action) {
51
45
  const messageAsString = JSON.stringify(action);
52
- this._log.trace(EVENTS.SEND, messageAsString);
46
+ this._log.trace({ data: action }, 'send');
53
47
  this._webSocket.send(messageAsString + '\n ');
54
48
  }
55
49
 
56
50
  _onMessage(rawData) {
57
51
  const data = _.isString(rawData) ? rawData : rawData.toString('utf8');
58
- this._log.trace(EVENTS.GET, data);
52
+ this._log.trace({ data }, 'get');
59
53
 
60
54
  try {
61
55
  let action;
@@ -84,16 +78,17 @@ class DetoxConnection {
84
78
  this._handler.onError(handlerError, action);
85
79
  }
86
80
  } catch (error) {
87
- this._log.warn({ ...EVENTS.ERROR }, error instanceof DetoxRuntimeError ? error.message : `${error}`);
81
+ this._log.warn({ error }, 'Caught unhandled error:');
88
82
  }
89
83
  }
90
84
 
91
- _onError(e) {
92
- this._log.warn(EVENTS.SOCKET_ERROR, DetoxRuntimeError.format(e));
85
+ _onError(error) {
86
+ this._log.warn({ error }, 'Caught socket error:');
93
87
  }
94
88
 
95
89
  _onClose() {
96
90
  this._sessionManager.unregisterConnection(this._webSocket);
91
+ this._log.debug.end();
97
92
  }
98
93
  }
99
94
 
@@ -4,7 +4,7 @@ const WebSocket = require('ws');
4
4
 
5
5
  const { DetoxInternalError, DetoxRuntimeError } = require('../errors');
6
6
  const Deferred = require('../utils/Deferred');
7
- const log = require('../utils/logger').child({ __filename });
7
+ const log = require('../utils/logger').child({ cat: 'ws-server,ws' });
8
8
 
9
9
  const DetoxSessionManager = require('./DetoxSessionManager');
10
10
 
@@ -40,18 +40,16 @@ class DetoxServer {
40
40
  await this._startListening();
41
41
 
42
42
  const level = this._options.standalone ? 'info' : 'debug';
43
- log[level]({ event: 'WSS_CREATE' }, `Detox server listening on localhost:${this.port}...`);
43
+ log[level](`Detox server listening on localhost:${this.port}...`);
44
44
  }
45
45
 
46
46
  async close() {
47
47
  try {
48
48
  await this._closeWithTimeout(10000);
49
- log.debug({ event: 'WSS_CLOSE' }, 'Detox server has been closed gracefully');
50
- } catch (e) {
51
- log.warn({ event: 'ERROR' },
52
- `Detox server has been closed abruptly! See the error details below:\n`
53
- + DetoxRuntimeError.format(e) + '\n'
54
- + DetoxRuntimeError.reportIssue
49
+ log.debug('Detox server has been closed gracefully');
50
+ } catch (err) {
51
+ log.warn({ err },
52
+ `Detox server has been closed abruptly! See the error details below:`
55
53
  );
56
54
  }
57
55
  }
@@ -90,8 +88,7 @@ class DetoxServer {
90
88
  } else if (this._closing) {
91
89
  this._closing.reject(err);
92
90
  } else {
93
- const formattedError = DetoxRuntimeError.format(err);
94
- log.error('Detox server has got an unhandled error:\n' + formattedError);
91
+ log.error({ err }, 'Detox server has got an unhandled error:');
95
92
  }
96
93
  }
97
94
 
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  const DetoxInternalError = require('../errors/DetoxInternalError');
3
- const log = require('../utils/logger').child({ __filename });
3
+ const log = require('../utils/logger').child({ cat: 'ws-server,ws-session' });
4
4
 
5
5
  class DetoxSession {
6
6
  /**
@@ -17,7 +17,7 @@ class DetoxSession {
17
17
  /** @type {boolean | null} */
18
18
  this._pendingTesterStatus = null;
19
19
 
20
- log.trace({ event: 'SESSION_CREATED' }, `created session ${id}`);
20
+ log.trace(`created session ${id}`);
21
21
  }
22
22
 
23
23
  get id() {
@@ -120,7 +120,7 @@ class DetoxSession {
120
120
  }
121
121
 
122
122
  _notifyAboutAppConnect() {
123
- log.trace({ event: 'SESSION_JOINED' }, `app joined session ${this.id}`);
123
+ log.trace(`app joined session ${this.id}`);
124
124
 
125
125
  if (!this._tester) {
126
126
  return;
@@ -132,7 +132,7 @@ class DetoxSession {
132
132
  }
133
133
 
134
134
  _notifyAboutAppDisconnect() {
135
- log.trace({ event: 'SESSION_TORN' }, `app exited session ${this.id}`);
135
+ log.trace(`app exited session ${this.id}`);
136
136
 
137
137
  if (!this._tester) {
138
138
  return;
@@ -144,11 +144,11 @@ class DetoxSession {
144
144
  }
145
145
 
146
146
  _notifyAboutTesterConnect() {
147
- log.trace({ event: 'SESSION_JOINED' }, `tester joined session ${this.id}`);
147
+ log.trace(`tester joined session ${this.id}`);
148
148
  }
149
149
 
150
150
  _notifyAboutTesterDisconnect() {
151
- log.trace({ event: 'SESSION_TORN' }, `tester exited session ${this.id}`);
151
+ log.trace(`tester exited session ${this.id}`);
152
152
 
153
153
  if (!this._app) {
154
154
  return;
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  const DetoxInternalError = require('../errors/DetoxInternalError');
3
- const log = require('../utils/logger').child({ __filename });
3
+ const log = require('../utils/logger').child({ cat: 'ws-server,ws' });
4
4
 
5
5
  const DetoxConnection = require('./DetoxConnection');
6
6
  const DetoxSession = require('./DetoxSession');
@@ -1,7 +1,6 @@
1
1
  // @ts-nocheck
2
2
  const { serializeError } = require('serialize-error');
3
3
 
4
- const DetoxError = require('../../errors/DetoxError');
5
4
  const DetoxInternalError = require('../../errors/DetoxInternalError');
6
5
 
7
6
  class RegisteredConnectionHandler {
@@ -41,7 +40,7 @@ class RegisteredConnectionHandler {
41
40
  messageId: action && action.messageId,
42
41
  });
43
42
  } catch (err) {
44
- this._api.log.error('Cannot forward the error details to the tester due to the error:\n' + DetoxError.format(err));
43
+ this._api.log.error({ err }, 'Cannot forward the error details to the tester due to the error:');
45
44
  throw error;
46
45
  }
47
46
  }
package/src/symbols.js CHANGED
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * @type {{
3
+ * readonly cleanup: unique symbol;
3
4
  * readonly config: unique symbol;
4
- * readonly globalSetup: unique symbol;
5
- * readonly globalTeardown: unique symbol;
5
+ * readonly getStatus: unique symbol;
6
+ * readonly init: unique symbol;
7
+ * readonly installWorker: unique symbol;
8
+ * readonly logger: unique symbol;
6
9
  * readonly onHookFailure: unique symbol;
7
10
  * readonly onHookStart: unique symbol;
8
11
  * readonly onHookSuccess: unique symbol;
@@ -18,8 +21,7 @@
18
21
  * readonly reportFailedTests: unique symbol;
19
22
  * readonly resolveConfig: unique symbol;
20
23
  * readonly session: unique symbol;
21
- * readonly setup: unique symbol;
22
- * readonly teardown: unique symbol;
24
+ * readonly uninstallWorker: unique symbol;
23
25
  * readonly worker: unique symbol;
24
26
  * }}
25
27
  */
@@ -44,13 +46,15 @@ module.exports = {
44
46
  //#endregion
45
47
 
46
48
  //#region Main
49
+ cleanup: Symbol('cleanup'),
47
50
  config: Symbol('config'),
48
- globalSetup: Symbol('globalSetup'),
49
- globalTeardown: Symbol('globalTeardown'),
51
+ getStatus: Symbol('getStatus'),
52
+ init: Symbol('init'),
53
+ installWorker: Symbol('installWorker'),
54
+ logger: Symbol('logger'),
50
55
  resolveConfig: Symbol('resolveConfig'),
51
56
  session: Symbol('session'),
52
- setup: Symbol('setup'),
53
- teardown: Symbol('teardown'),
57
+ uninstallWorker: Symbol('uninstallWorker'),
54
58
  worker: Symbol('worker'),
55
59
  //#endregion
56
60
  };
@@ -3,7 +3,7 @@ const { exec } = require('child-process-promise');
3
3
  const _ = require('lodash');
4
4
 
5
5
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
6
- const rootLogger = require('../logger').child({ __filename });
6
+ const rootLogger = require('../logger').child({ cat: ['child-process', 'child-process-exec'] });
7
7
  const retry = require('../retry');
8
8
 
9
9
  const execsCounter = require('./opsCounter');
@@ -2,7 +2,7 @@
2
2
  const { spawn } = require('child-process-promise');
3
3
  const _ = require('lodash');
4
4
 
5
- const rootLogger = require('../logger').child({ __filename });
5
+ const rootLogger = require('../logger').child({ cat: ['child-process', 'child-process-spawn'] });
6
6
  const { escape } = require('../pipeCommands');
7
7
  const retry = require('../retry');
8
8