detox 20.0.14-next-is-hittable-check-2.0 → 20.0.14-prerelease.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. package/Detox-android/com/wix/detox/{20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-javadoc.jar → 20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-sources.jar → 20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.aar → 20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar} +0 -0
  12. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.pom → 20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-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/index.d.ts +3 -4
  29. package/internals.d.ts +26 -5
  30. package/local-cli/cli.js +1 -1
  31. package/local-cli/init.js +1 -1
  32. package/local-cli/test.js +6 -6
  33. package/local-cli/test.test.js +14 -18
  34. package/local-cli/testCommand/TestRunnerCommand.js +75 -86
  35. package/local-cli/testCommand/builder.js +0 -1
  36. package/local-cli/testCommand/middlewares.js +1 -11
  37. package/local-cli/testCommand/warnings.js +0 -3
  38. package/package.json +22 -8
  39. package/runners/deprecation.js +42 -44
  40. package/runners/jest/index.d.ts +60 -0
  41. package/runners/jest/index.js +3 -8
  42. package/runners/jest/reporters/DetoxReporter.js +21 -10
  43. package/runners/jest/testEnvironment/index.js +57 -41
  44. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +7 -3
  45. package/runners/jest/testEnvironment/listeners/SpecReporter.js +12 -14
  46. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +1 -5
  47. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  48. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -1
  49. package/src/DetoxWorker.js +84 -46
  50. package/src/artifacts/ArtifactsManager.js +6 -6
  51. package/src/configuration/collectCliConfig.js +1 -12
  52. package/src/configuration/composeRunnerConfig.js +4 -3
  53. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
  54. package/src/errors/DetoxConfigErrorComposer.js +6 -1
  55. package/src/ipc/SessionState.js +7 -5
  56. package/src/logger/DetoxLogger.js +1 -19
  57. package/src/logger/index.js +1 -0
  58. package/src/logger/utils/CategoryThreadDispatcher.js +7 -29
  59. package/src/logger/utils/DetoxLogFinalizer.js +134 -0
  60. package/src/logger/utils/ThreadDispatcher.js +5 -25
  61. package/src/logger/utils/customConsoleLogger.js +4 -3
  62. package/src/logger/utils/streamUtils.js +34 -26
  63. package/src/realms/DetoxContext.js +8 -7
  64. package/src/realms/DetoxPrimaryContext.js +22 -82
  65. package/src/realms/DetoxSecondaryContext.js +0 -8
  66. package/src/utils/argparse.js +11 -0
  67. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-javadoc.jar.md5 +0 -1
  68. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-javadoc.jar.sha1 +0 -1
  69. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-javadoc.jar.sha256 +0 -1
  70. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-javadoc.jar.sha512 +0 -1
  71. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-sources.jar.md5 +0 -1
  72. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-sources.jar.sha1 +0 -1
  73. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-sources.jar.sha256 +0 -1
  74. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0-sources.jar.sha512 +0 -1
  75. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.aar.md5 +0 -1
  76. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.aar.sha1 +0 -1
  77. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.aar.sha256 +0 -1
  78. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.aar.sha512 +0 -1
  79. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.pom.md5 +0 -1
  80. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.pom.sha1 +0 -1
  81. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.pom.sha256 +0 -1
  82. package/Detox-android/com/wix/detox/20.0.14-next-is-hittable-check-2.0/detox-20.0.14-next-is-hittable-check-2.0.pom.sha512 +0 -1
  83. package/runners/jest/deprecation.js +0 -25
  84. package/src/configuration/utils/warnings.js +0 -12
@@ -1,3 +1,4 @@
1
+ const CAF = require('caf');
1
2
  const _ = require('lodash');
2
3
 
3
4
  const Client = require('./client/Client');
@@ -11,7 +12,6 @@ const uuid = require('./utils/uuid');
11
12
  class DetoxWorker {
12
13
  constructor(context) {
13
14
  this._context = context;
14
- this._isCleaningUp = false;
15
15
  this._injectedGlobalProperties = [];
16
16
  this._config = context[symbols.config];
17
17
  this._runtimeErrorComposer = new DetoxRuntimeErrorComposer(this._config);
@@ -33,6 +33,18 @@ class DetoxWorker {
33
33
  onError: this._onEmitError.bind(this),
34
34
  });
35
35
 
36
+
37
+ /** @type {DetoxInternals.RuntimeConfig['apps']} */
38
+ this._appsConfig = null;
39
+ /** @type {DetoxInternals.RuntimeConfig['artifacts']} */
40
+ this._artifactsConfig = null;
41
+ /** @type {DetoxInternals.RuntimeConfig['behavior']} */
42
+ this._behaviorConfig = null;
43
+ /** @type {DetoxInternals.RuntimeConfig['device']} */
44
+ this._deviceConfig = null;
45
+ /** @type {DetoxInternals.RuntimeConfig['session']} */
46
+ this._sessionConfig = null;
47
+
36
48
  /** @type {string} */
37
49
  this.id = 'worker';
38
50
  /** @type {Detox.Device} */
@@ -54,11 +66,23 @@ class DetoxWorker {
54
66
  this.trace = this._context.trace;
55
67
  /** @deprecated */
56
68
  this.traceCall = this._context.traceCall;
57
- }
58
69
 
59
- async init() {
60
- if (this._isCleaningUp) return;
70
+ this._reinstallAppsOnDevice = CAF(this._reinstallAppsOnDevice.bind(this));
71
+ this._initToken = new CAF.cancelToken();
72
+
73
+ this._cafWrap([
74
+ 'init',
75
+ 'onRunDescribeStart',
76
+ 'onTestStart',
77
+ 'onHookFailure',
78
+ 'onTestFnFailure',
79
+ 'onTestDone',
80
+ 'onRunDescribeFinish',
81
+ ]);
82
+ }
61
83
 
84
+ /** @this {DetoxWorker} */
85
+ init = function* (signal) {
62
86
  const {
63
87
  apps: appsConfig,
64
88
  artifacts: artifactsConfig,
@@ -72,6 +96,7 @@ class DetoxWorker {
72
96
  this._behaviorConfig = behaviorConfig;
73
97
  this._deviceConfig = deviceConfig;
74
98
  this._sessionConfig = sessionConfig;
99
+ // @ts-ignore
75
100
  this._sessionConfig.sessionId = sessionConfig.sessionId || uuid.UUID();
76
101
  this._runtimeErrorComposer.appsConfig = this._appsConfig;
77
102
 
@@ -83,8 +108,7 @@ class DetoxWorker {
83
108
  }
84
109
  };
85
110
 
86
- await this._client.connect();
87
- if (this._isCleaningUp) return;
111
+ yield this._client.connect();
88
112
 
89
113
  const invocationManager = new InvocationManager(this._client);
90
114
 
@@ -101,8 +125,7 @@ class DetoxWorker {
101
125
  } = environmentFactory.createFactories(this._deviceConfig);
102
126
 
103
127
  const envValidator = envValidatorFactory.createValidator();
104
- await envValidator.validate();
105
- if (this._isCleaningUp) return;
128
+ yield envValidator.validate();
106
129
 
107
130
  const commonDeps = {
108
131
  invocationManager,
@@ -113,8 +136,7 @@ class DetoxWorker {
113
136
 
114
137
  this._artifactsManager = artifactsManagerFactory.createArtifactsManager(this._artifactsConfig, commonDeps);
115
138
  this._deviceAllocator = deviceAllocatorFactory.createDeviceAllocator(commonDeps);
116
- this._deviceCookie = await this._deviceAllocator.allocate(this._deviceConfig);
117
- if (this._isCleaningUp) return;
139
+ this._deviceCookie = yield this._deviceAllocator.allocate(this._deviceConfig);
118
140
 
119
141
  this.device = runtimeDeviceFactory.createRuntimeDevice(
120
142
  this._deviceCookie,
@@ -125,7 +147,6 @@ class DetoxWorker {
125
147
  deviceConfig: this._deviceConfig,
126
148
  sessionConfig,
127
149
  });
128
- if (this._isCleaningUp) return;
129
150
 
130
151
  const matchers = matchersFactory.createMatchers({
131
152
  invocationManager,
@@ -146,26 +167,22 @@ class DetoxWorker {
146
167
  }
147
168
 
148
169
  // @ts-ignore
149
- await this.device.installUtilBinaries();
150
- if (this._isCleaningUp) return;
170
+ yield this.device.installUtilBinaries();
151
171
 
152
172
  if (behaviorConfig.init.reinstallApp) {
153
- await this._reinstallAppsOnDevice();
154
- if (this._isCleaningUp) return;
173
+ yield this._reinstallAppsOnDevice(signal);
155
174
  }
156
175
 
157
176
  const appAliases = Object.keys(this._appsConfig);
158
177
  if (appAliases.length === 1) {
159
- await this.device.selectApp(appAliases[0]);
178
+ yield this.device.selectApp(appAliases[0]);
160
179
  } else {
161
- await this.device.selectApp(null);
180
+ yield this.device.selectApp(null);
162
181
  }
163
-
164
- return this;
165
- }
182
+ };
166
183
 
167
184
  async cleanup() {
168
- this._isCleaningUp = true;
185
+ this._initToken.abort('CLEANUP');
169
186
 
170
187
  for (const key of this._injectedGlobalProperties) {
171
188
  delete DetoxWorker.global[key];
@@ -198,38 +215,45 @@ class DetoxWorker {
198
215
  return this._context.log;
199
216
  }
200
217
 
201
- onRunDescribeStart = async (...args) => this._artifactsManager.onRunDescribeStart(...args);
202
- onTestStart = async (testSummary) => {
203
- if (this._isCleaningUp) return;
218
+ onRunDescribeStart = function* (_signal, ...args) {
219
+ yield this._artifactsManager.onRunDescribeStart(...args);
220
+ };
221
+
222
+ onTestStart = function* (_signal, testSummary) {
204
223
  this._validateTestSummary('beforeEach', testSummary);
205
224
 
206
- if (this._isCleaningUp) return;
207
- await this._dumpUnhandledErrorsIfAny({
225
+ yield this._dumpUnhandledErrorsIfAny({
208
226
  pendingRequests: false,
209
227
  testName: testSummary.fullName,
210
228
  });
211
229
 
212
- if (this._isCleaningUp) return;
213
- await this._artifactsManager.onTestStart(testSummary);
230
+ yield this._artifactsManager.onTestStart(testSummary);
231
+ };
232
+
233
+ onHookFailure = function* (_signal, ...args) {
234
+ yield this._artifactsManager.onHookFailure(...args);
235
+ };
236
+
237
+ onTestFnFailure = function* (_signal, ...args) {
238
+ yield this._artifactsManager.onTestFnFailure(...args);
214
239
  };
215
- onHookFailure = async (...args) => this._artifactsManager.onHookFailure(...args);
216
- onTestFnFailure = async (...args) => this._artifactsManager.onTestFnFailure(...args);
217
- onTestDone = async (testSummary) => {
218
- if (this._isCleaningUp) return;
240
+
241
+ onTestDone = function* (_signal, testSummary) {
219
242
  this._validateTestSummary('afterEach', testSummary);
220
243
 
221
- if (this._isCleaningUp) return;
222
- await this._artifactsManager.onTestDone(testSummary);
244
+ yield this._artifactsManager.onTestDone(testSummary);
223
245
 
224
- if (this._isCleaningUp) return;
225
- await this._dumpUnhandledErrorsIfAny({
246
+ yield this._dumpUnhandledErrorsIfAny({
226
247
  pendingRequests: testSummary.timedOut,
227
248
  testName: testSummary.fullName,
228
249
  });
229
250
  };
230
- onRunDescribeFinish = async (...args) => this._artifactsManager.onRunDescribeFinish(...args);
231
251
 
232
- async _reinstallAppsOnDevice() {
252
+ onRunDescribeFinish = function* (_signal, ...args) {
253
+ yield this._artifactsManager.onRunDescribeFinish(...args);
254
+ };
255
+
256
+ *_reinstallAppsOnDevice(_signal) {
233
257
  const appNames = _(this._appsConfig)
234
258
  .map((config, key) => [key, `${config.binaryPath}:${config.testBinaryPath}`])
235
259
  .uniqBy(1)
@@ -237,17 +261,13 @@ class DetoxWorker {
237
261
  .value();
238
262
 
239
263
  for (const appName of appNames) {
240
- await this.device.selectApp(appName);
241
- if (this._isCleaningUp) return;
242
- await this.device.uninstallApp();
243
- if (this._isCleaningUp) return;
264
+ yield this.device.selectApp(appName);
265
+ yield this.device.uninstallApp();
244
266
  }
245
267
 
246
268
  for (const appName of appNames) {
247
- await this.device.selectApp(appName);
248
- if (this._isCleaningUp) return;
249
- await this.device.installApp();
250
- if (this._isCleaningUp) return;
269
+ yield this.device.selectApp(appName);
270
+ yield this.device.installApp();
251
271
  }
252
272
  }
253
273
 
@@ -279,6 +299,24 @@ class DetoxWorker {
279
299
  error
280
300
  );
281
301
  }
302
+
303
+ _cafWrap(methodNames) {
304
+ for (const methodName of methodNames) {
305
+ const cafMethod = CAF(this[methodName].bind(this));
306
+ this[methodName] = async (...args) => {
307
+ try {
308
+ await cafMethod(this._initToken.signal, ...args);
309
+ } catch (e) {
310
+ if (e !== 'CLEANUP') {
311
+ throw e;
312
+ }
313
+ }
314
+
315
+ return this;
316
+ };
317
+ }
318
+ }
319
+
282
320
  }
283
321
 
284
322
  /**
@@ -46,13 +46,13 @@ class ArtifactsManager extends EventEmitter {
46
46
  _resolveArtifactsPathBuilder(pathBuilder, rootDir) {
47
47
  if (typeof pathBuilder === 'string') {
48
48
  pathBuilder = resolveModuleFromPath(pathBuilder);
49
+ }
49
50
 
50
- if (typeof pathBuilder === 'function') {
51
- try {
52
- pathBuilder = pathBuilder({ rootDir });
53
- } catch (e) {
54
- pathBuilder = new pathBuilder({ rootDir });
55
- }
51
+ if (typeof pathBuilder === 'function') {
52
+ try {
53
+ pathBuilder = pathBuilder({ rootDir });
54
+ } catch (e) {
55
+ pathBuilder = new pathBuilder({ rootDir });
56
56
  }
57
57
  }
58
58
 
@@ -1,9 +1,6 @@
1
1
  const _ = require('lodash');
2
2
 
3
3
  const argparse = require('../utils/argparse');
4
- const log = require('../utils/logger').child({ cat: 'config' });
5
-
6
- const { DEVICE_LAUNCH_ARGS_GENERIC_DEPRECATION } = require('./utils/warnings');
7
4
 
8
5
  const asBoolean = (value) => {
9
6
  if (typeof value === 'boolean') {
@@ -25,14 +22,6 @@ const asNumber = (value) => {
25
22
  : undefined;
26
23
  };
27
24
 
28
- const deprecateDeviceLaunchArgs = (value) => {
29
- if (value) {
30
- log.warn(DEVICE_LAUNCH_ARGS_GENERIC_DEPRECATION);
31
- }
32
-
33
- return value;
34
- };
35
-
36
25
  function collectCliConfig({ argv }) {
37
26
  const env = (key) => argparse.getArgValue(key);
38
27
  const get = (key, fallback) => {
@@ -51,7 +40,7 @@ function collectCliConfig({ argv }) {
51
40
  configPath: get('config-path'),
52
41
  configuration: get('configuration'),
53
42
  debugSynchronization: asNumber(get('debug-synchronization')),
54
- deviceBootArgs: get('device-boot-args', deprecateDeviceLaunchArgs(argparse.getEnvValue('device-launch-args'))),
43
+ deviceBootArgs: get('device-boot-args'),
55
44
  appLaunchArgs: get('app-launch-args'),
56
45
  deviceName: get('device-name'),
57
46
  forceAdbInstall: asBoolean(get('force-adb-install')),
@@ -120,9 +120,10 @@ function hasEmptyPositionalArgs(value, key) {
120
120
  * @param {Detox.DetoxTestRunnerConfig} config
121
121
  */
122
122
  function inspectBrkHookDefault(config) {
123
- config.args.$0 = /* istanbul ignore if */ os.platform() === 'win32'
124
- ? `node --inspect-brk ./node_modules/jest/bin/jest.js`
125
- : `node --inspect-brk ./node_modules/.bin/jest`;
123
+ /* istanbul ignore next */
124
+ config.args.$0 = os.platform() !== 'win32'
125
+ ? `node --inspect-brk ./node_modules/.bin/jest`
126
+ : `node --inspect-brk ./node_modules/jest/bin/jest.js`;
126
127
  config.args.runInBand = true;
127
128
  delete config.args.w;
128
129
  delete config.args.workers;
@@ -93,7 +93,7 @@ class AppleSimUtils {
93
93
  `(https://developer.apple.com/xcode/). In case you already have the latest Xcode version installed, ` +
94
94
  `try run the command: \`sudo xcode-select -s /Applications/Xcode.app\`. If you are running tests from CI, ` +
95
95
  `we recommend running them with "--headless" device configuration (see: ` +
96
- `https://wix.github.io/Detox/docs/next/api/configuration/#device-configurations).`
96
+ `https://wix.github.io/Detox/docs/next/cli/test/#options).`
97
97
  );
98
98
  }
99
99
 
@@ -664,7 +664,12 @@ Examine your Detox config${this._atPath()}`,
664
664
  }
665
665
 
666
666
  invalidTestRunnerProperty(isGlobal) {
667
- const testRunner = _.get(this.contents, ['testRunner']);
667
+ const testRunner = _.get(
668
+ isGlobal
669
+ ? this.contents
670
+ : this._getSelectedConfiguration(),
671
+ ['testRunner']
672
+ );
668
673
 
669
674
  return new DetoxConfigError({
670
675
  message: `testRunner should be an object, not a ${typeof testRunner}`,
@@ -1,12 +1,15 @@
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 {
6
10
  constructor({
7
- id = uuid.UUID(),
11
+ id = '',
8
12
  contexts = [],
9
- detoxConfigSnapshotPath = '',
10
13
  detoxConfig = null,
11
14
  detoxIPCServer = '',
12
15
  testResults = [],
@@ -15,7 +18,6 @@ class SessionState {
15
18
  }) {
16
19
  this.id = id;
17
20
  this.contexts = contexts;
18
- this.detoxConfigSnapshotPath = detoxConfigSnapshotPath;
19
21
  this.detoxConfig = detoxConfig;
20
22
  this.detoxIPCServer = detoxIPCServer;
21
23
  this.testResults = testResults;
@@ -42,7 +44,7 @@ class SessionState {
42
44
 
43
45
  static reviver(key, val) {
44
46
  if (typeof val === 'object' && val !== null && typeof val.$fn == 'string') {
45
- return eval(val.$fn);
47
+ return vm.runInContext(val.$fn, context);
46
48
  } else {
47
49
  return val;
48
50
  }
@@ -71,25 +71,7 @@ class DetoxLogger {
71
71
  .installFileStream(this.file)
72
72
  .installDebugStream(this.config);
73
73
 
74
- this._sharedConfig.dispatcher = new CategoryThreadDispatcher({
75
- logger: this,
76
- categories: {
77
- 'lifecycle': [0],
78
- 'cli': [1],
79
- 'logger': [2],
80
- 'ipc': [29],
81
- 'ws-server': [50, 99],
82
- 'ws-client': [100, 149],
83
- 'device': [150, 159],
84
- 'artifacts-manager': [300],
85
- 'artifacts-plugin': [310, 349],
86
- 'artifact': [350, 399],
87
- 'child-process': [400, 499],
88
- 'default': [999],
89
- 'user': [10000, 10999]
90
- },
91
- });
92
-
74
+ this._sharedConfig.dispatcher = new CategoryThreadDispatcher();
93
75
  this._sharedConfig.messageStack = new MessageStack();
94
76
 
95
77
  this.overrideConsole();
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  DetoxLogger: require('./DetoxLogger'),
3
+ DetoxLogFinalizer: require('./utils/DetoxLogFinalizer'),
3
4
  installLegacyTracerInterface: require('./utils/tracerLegacy').install,
4
5
  };
@@ -1,23 +1,9 @@
1
- const _ = require('lodash');
2
-
3
1
  const ThreadDispatcher = require('./ThreadDispatcher');
4
2
 
5
3
  class CategoryThreadDispatcher {
6
- /**
7
- * @param {object} config
8
- * @param {Record<string, [number, number?]>} config.categories
9
- * @param {Detox.Logger} config.logger
10
- */
11
- constructor(config) {
12
- this.categories = config.categories;
13
- this.dispatchers = _.mapValues(this.categories, (range, name) => {
14
- return new ThreadDispatcher({
15
- name,
16
- logger: config.logger,
17
- min: range[0],
18
- max: range[1] || range[0],
19
- });
20
- });
4
+ constructor() {
5
+ /** @type {Record<string, ThreadDispatcher>} */
6
+ this._dispatchers = {};
21
7
  }
22
8
 
23
9
  /**
@@ -38,20 +24,12 @@ class CategoryThreadDispatcher {
38
24
 
39
25
  /** @returns {ThreadDispatcher} */
40
26
  _resolveDispatcher(cat) {
41
- const mainCategory = cat ? cat.split(',', 1)[0] : '';
42
- return this.dispatchers[mainCategory] || this.dispatchers.default;
43
- }
44
-
45
- categorize(tid) {
46
- return _.findKey(this.categories, ([min, max]) => min <= tid && tid <= max) || 'default';
47
- }
48
-
49
- threadize(cat) {
50
- if (!cat) {
51
- return this.categories.default[0];
27
+ const mainCategory = cat ? cat.split(',', 1)[0] : 'default';
28
+ if (!this._dispatchers[mainCategory]) {
29
+ this._dispatchers[mainCategory] = new ThreadDispatcher(mainCategory);
52
30
  }
53
31
 
54
- return _.find(this.categories, (_, key) => key === cat[0]);
32
+ return this._dispatchers[mainCategory];
55
33
  }
56
34
  }
57
35
 
@@ -0,0 +1,134 @@
1
+ const path = require('path');
2
+ const { promisify } = require('util');
3
+
4
+ const fs = require('fs-extra');
5
+ const glob = require('glob');
6
+ const pipe = require('multipipe');
7
+
8
+ const temporary = require('../../artifacts/utils/temporaryPath');
9
+
10
+ const globAsync = promisify(glob);
11
+ const globSync = glob.sync;
12
+ const streamUtils = () => require('../../logger/utils/streamUtils');
13
+
14
+ /**
15
+ * @typedef DetoxLogFinalizerConfig
16
+ * @property {import('../../ipc/SessionState')} session
17
+ */
18
+
19
+ class DetoxLogFinalizer {
20
+ /** @param {DetoxLogFinalizerConfig} config */
21
+ constructor(config) {
22
+ this._session = config.session;
23
+ }
24
+
25
+ createEventStream() {
26
+ const sessionId = this._session.id;
27
+ const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
28
+
29
+ return streamUtils()
30
+ .uniteSessionLogs(logs)
31
+ .pipe(streamUtils().chromeTraceStream());
32
+ }
33
+
34
+ async finalize() {
35
+ const sessionId = this._session.id;
36
+ const logs = await globAsync(temporary.for.jsonl(`${sessionId}.*`));
37
+ if (logs.length === 0) {
38
+ return;
39
+ }
40
+
41
+ if (this._areLogsEnabled()) {
42
+ const rootDir = this._config.artifacts.rootDir;
43
+
44
+ await fs.mkdirp(rootDir);
45
+ const [out1Stream, out2Stream] = ['detox.log', 'detox.trace.json']
46
+ .map((filename) => fs.createWriteStream(path.join(rootDir, filename)));
47
+
48
+ const tidHashMap = await this._scanForThreadIds(logs);
49
+ const mergedStream = streamUtils().uniteSessionLogs(logs);
50
+
51
+ await Promise.all([
52
+ pipe(mergedStream, streamUtils().debugStream(this._config.logger.options), out1Stream),
53
+ pipe(mergedStream, streamUtils().chromeTraceStream(tidHashMap), streamUtils().writeJSON(), out2Stream),
54
+ ]);
55
+ }
56
+
57
+ await Promise.all(logs.map(filepath => fs.remove(filepath)));
58
+ }
59
+
60
+ finalizeSync() {
61
+ const sessionId = this._session.id;
62
+ const rootDir = this._config.artifacts.rootDir;
63
+ const logsEnabled = this._areLogsEnabled();
64
+
65
+ if (logsEnabled) {
66
+ fs.mkdirpSync(rootDir);
67
+ }
68
+
69
+ const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
70
+
71
+ for (const log of logs) {
72
+ if (logsEnabled) {
73
+ fs.moveSync(log, path.join(rootDir, path.basename(log)));
74
+ } else {
75
+ fs.removeSync(log);
76
+ }
77
+ }
78
+ }
79
+
80
+ /** @private */
81
+ get _config() {
82
+ // The config appears later in the lifecycle, so we need to access it lazily
83
+ return this._session.detoxConfig;
84
+ }
85
+
86
+ /** @private */
87
+ _areLogsEnabled() {
88
+ const { rootDir, plugins } = this._config.artifacts;
89
+ if (!rootDir || !plugins) {
90
+ return false;
91
+ }
92
+
93
+ if (!plugins.log.enabled) {
94
+ return false;
95
+ }
96
+
97
+ if (!plugins.log.keepOnlyFailedTestsArtifacts) {
98
+ return true;
99
+ }
100
+
101
+ return this._session.testResults.some(r => !r.success);
102
+ }
103
+
104
+ /** @private */
105
+ async _scanForThreadIds(logs) {
106
+ const processes = await new Promise((resolve, reject) => {
107
+ const result = {};
108
+ streamUtils().uniteSessionLogs(logs)
109
+ .on('end', () => resolve(result))
110
+ .on('error', (err) => reject(err))
111
+ .on('data', (event) => {
112
+ const { ph, pid, tid, cat } = event;
113
+ if (ph === 'B' || ph === 'i') {
114
+ const categories = (result[pid] = result[pid] || {});
115
+ const mainCategory = String(cat).split(',')[0];
116
+ const tids = (categories[mainCategory] = categories[mainCategory] || []);
117
+ if (!tids.includes(tid)) {
118
+ tids.push(tid);
119
+ }
120
+ }
121
+ });
122
+ });
123
+
124
+ const tidArray = Object.entries(processes).flatMap(([pid, categories]) => {
125
+ return Object.entries(categories).flatMap(([category, tids]) => {
126
+ return tids.map(tid => `${pid}:${category}:${tid}`);
127
+ });
128
+ });
129
+
130
+ return new Map(tidArray.map((hash, index) => [hash, index]));
131
+ }
132
+ }
133
+
134
+ module.exports = DetoxLogFinalizer;
@@ -2,17 +2,10 @@ const isUndefined = (x) => x === undefined;
2
2
 
3
3
  class ThreadDispatcher {
4
4
  /**
5
- * @param {object} options
6
- * @param {Detox.Logger} options.logger
7
- * @param {string} options.name
8
- * @param {number} options.min
9
- * @param {number} [options.max]
5
+ * @param {string} name
10
6
  */
11
- constructor({ logger, name, min, max = Infinity }) {
12
- this.logger = logger;
7
+ constructor(name) {
13
8
  this.name = name;
14
- this.min = min;
15
- this.max = max;
16
9
  this.stacks = [];
17
10
  this.threads = [];
18
11
  }
@@ -25,7 +18,7 @@ class ThreadDispatcher {
25
18
  const tid = this._findTID(id);
26
19
  this.threads[tid] = id;
27
20
  this.stacks[tid] = (this.stacks[tid] || 0) + 1;
28
- return this._transpose(tid);
21
+ return tid;
29
22
  }
30
23
 
31
24
  /**
@@ -33,8 +26,7 @@ class ThreadDispatcher {
33
26
  * @returns {number}
34
27
  */
35
28
  resolve(id) {
36
- const tid = this._findTID(id);
37
- return this._transpose(tid);
29
+ return this._findTID(id);
38
30
  }
39
31
 
40
32
  /**
@@ -46,7 +38,7 @@ class ThreadDispatcher {
46
38
  if (this.stacks[tid] && --this.stacks[tid] === 0) {
47
39
  delete this.threads[tid];
48
40
  }
49
- return this._transpose(tid);
41
+ return tid;
50
42
  }
51
43
 
52
44
  /**
@@ -64,18 +56,6 @@ class ThreadDispatcher {
64
56
  }
65
57
  return tid === -1 ? this.threads.length : tid;
66
58
  }
67
-
68
- _transpose(id) {
69
- const result = this.min + id;
70
- if (result > this.max) {
71
- this.logger.warn(
72
- { cat: ['logger', 'thread-dispatcher'] },
73
- `${this.name} trace thread dispatcher has run out of available thread IDs: ${this.min}..${this.max}`
74
- );
75
- }
76
-
77
- return Math.min(result, this.max);
78
- }
79
59
  }
80
60
 
81
61
  module.exports = ThreadDispatcher;