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
package/internals.d.ts CHANGED
@@ -3,33 +3,40 @@
3
3
 
4
4
  declare global {
5
5
  namespace DetoxInternals {
6
+ type DetoxStatus = 'inactive' | 'init' | 'active' | 'cleanup';
7
+
6
8
  type Facade = {
7
9
  // region Initialization
8
10
  /**
9
- * Use with a caution, when you still have no config, yet need to avoid {@link Facade#globalSetup}
11
+ * Use with a caution, when you still have no config, yet need to avoid {@link Facade#init}
10
12
  */
11
- resolveConfig(options?: Partial<DetoxGlobalSetupOptions>): Promise<RuntimeConfig>;
13
+ resolveConfig(options?: Partial<DetoxInitOptions>): Promise<RuntimeConfig>;
14
+
15
+ /**
16
+ *
17
+ */
18
+ getStatus(): DetoxStatus;
12
19
 
13
20
  /**
14
21
  * This is the phase where Detox reads its configuration, starts a server.
15
22
  */
16
- globalSetup(options?: Partial<DetoxGlobalSetupOptions>): Promise<void>;
23
+ init(options?: Partial<DetoxInitOptions>): Promise<void>;
17
24
 
18
25
  /**
19
- * This is the phase where Detox loads its expection library and starts a device.
26
+ * This is the phase where Detox loads its expectation library and starts a device.
20
27
  */
21
- setup(options?: Partial<DetoxConfigurationSetupOptions>): Promise<void>;
28
+ installWorker(options?: Partial<DetoxInstallWorkerOptions>): Promise<void>;
22
29
 
23
30
  /**
24
- * The teardown phase deallocates the device.
31
+ * Deallocates the device.
25
32
  */
26
- teardown(): Promise<void>;
33
+ uninstallWorker(): Promise<void>;
27
34
 
28
35
  /**
29
36
  * The global cleanup phase should happen after all the tests have finished.
30
37
  * This is the phase where the Detox server shuts down.
31
38
  */
32
- globalTeardown(): Promise<void>;
39
+ cleanup(): Promise<void>;
33
40
  // endregion
34
41
 
35
42
  // region Lifecycle
@@ -59,28 +66,69 @@ declare global {
59
66
 
60
67
  readonly config: RuntimeConfig;
61
68
  readonly log: Detox.Logger;
62
- readonly trace: Detox.Tracer;
63
69
  readonly session: SessionState;
64
70
 
65
- readonly worker: unknown;
71
+ readonly worker: Worker;
72
+ }
73
+
74
+ interface Worker extends Detox.DetoxExportWrapper {
75
+ readonly id: string;
66
76
  }
67
77
 
68
- type DetoxGlobalSetupOptions = {
78
+ type DetoxInitOptions = {
69
79
  cwd: string;
70
80
  argv: Record<string, unknown>;
71
81
  testRunnerArgv: Record<string, unknown>;
72
82
  override: Partial<Detox.DetoxConfig>;
83
+ /** @inheritDoc */
84
+ global: NodeJS.Global;
85
+ /**
86
+ * Worker ID. Used to distinguish allocated workers in parallel test execution environment.
87
+ *
88
+ * If explicitly set to null, tells {@link Facade#init} to skip {@link Facade#installWorker} call.
89
+ * Useful for complex test runner integrations, where you have to install the worker via a separate call,
90
+ * when the environment is ready for that.
91
+ *
92
+ * @default 'worker'
93
+ */
94
+ workerId: string | null;
73
95
  };
74
96
 
75
- type DetoxConfigurationSetupOptions = {
97
+ type DetoxInstallWorkerOptions = {
98
+ /**
99
+ * Used for integration with sandboxed test environments.
100
+ * {@link DetoxInternals.Facade#setup} might override {@link Console} methods
101
+ * to integrate it with Detox loggeing subsystem.
102
+ */
76
103
  global: NodeJS.Global;
77
- workerId: number;
104
+ /**
105
+ * Worker ID. Used to distinguish allocated workers in parallel test execution environment.
106
+ *
107
+ * @default 'worker'
108
+ */
109
+ workerId: string;
78
110
  };
79
111
 
80
112
  type SessionState = Readonly<{
113
+ /**
114
+ * Randomly generated ID for the entire Detox test session, including retries.
115
+ */
116
+ id: string;
117
+ /**
118
+ * Permanently failed test file paths.
119
+ */
81
120
  failedTestFiles: string[];
121
+ /**
122
+ * Failed test file paths suggested to retry via Detox CLI mechanism.
123
+ */
82
124
  testFilesToRetry: string[];
125
+ /**
126
+ * Retry index of the test session: 0..retriesCount.
127
+ */
83
128
  testSessionIndex: number;
129
+ /**
130
+ * TODO
131
+ */
84
132
  workersCount: number;
85
133
  }>;
86
134
 
@@ -95,14 +143,14 @@ declare global {
95
143
  apps: Record<string, Readonly<Detox.DetoxAppConfig>>;
96
144
  artifacts: Readonly<Detox.DetoxArtifactsConfig>;
97
145
  behavior: Readonly<Detox.DetoxBehaviorConfig>;
98
- cli: Readonly<DetoxCLIConfig>;
146
+ cli: Readonly<CLIConfig>;
99
147
  device: Readonly<Detox.DetoxDeviceConfig>;
100
148
  logger: Readonly<Detox.DetoxLoggerConfig>;
101
149
  testRunner: Readonly<Detox.DetoxTestRunnerConfig>;
102
150
  session: Readonly<Detox.DetoxSessionConfig>;
103
151
  }>;
104
152
 
105
- type DetoxCLIConfig = Readonly<Partial<{
153
+ type CLIConfig = Readonly<Partial<{
106
154
  appLaunchArgs: string;
107
155
  artifactsLocation: string;
108
156
  captureViewHierarchy: string;
package/local-cli/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  const yargs = require('yargs');
3
3
 
4
4
  const DetoxError = require('../src/errors/DetoxError');
5
- const logger = require('../src/utils/logger').child({ __filename });
5
+ const logger = require('../src/utils/logger').child({ cat: 'cli' });
6
6
 
7
7
  yargs
8
8
  .scriptName('detox')
@@ -4,7 +4,7 @@ const path = require('path');
4
4
 
5
5
  const fs = require('fs-extra');
6
6
 
7
- const log = require('../src/utils/logger').child({ __filename });
7
+ const log = require('../src/utils/logger').child({ cat: 'cli' });
8
8
 
9
9
  module.exports.command = 'rebuild-framework-cache';
10
10
  module.exports.desc = 'Rebuilds a cached Detox framework for the current environment in ~/Library/Detox. The cached framework is unique for each combination of Xcode and Detox version. (macOS only)';
package/local-cli/test.js CHANGED
@@ -9,9 +9,10 @@ module.exports.middlewares = require('./testCommand/middlewares').default;
9
9
 
10
10
  module.exports.handler = async function test({ detoxArgs, runnerArgs }) {
11
11
  try {
12
- await detox.globalSetup({
12
+ await detox.init({
13
13
  argv: detoxArgs,
14
14
  testRunnerArgv: runnerArgs,
15
+ workerId: null,
15
16
  });
16
17
 
17
18
  const runnerCommand = new TestRunnerCommand()
@@ -21,6 +22,6 @@ module.exports.handler = async function test({ detoxArgs, runnerArgs }) {
21
22
 
22
23
  await runnerCommand.execute();
23
24
  } finally {
24
- await detox.globalTeardown();
25
+ await detox.cleanup();
25
26
  }
26
27
  };
@@ -504,7 +504,7 @@ describe('CLI', () => {
504
504
  return {
505
505
  ...mockCall,
506
506
  fullCommand: _.chain(logger().log.mock.calls)
507
- .filter(([_level, _childMeta, meta]) => meta && meta.event === 'RUN_START')
507
+ .filter(([_level, _childMeta, meta]) => meta && meta.env)
508
508
  .get(index)
509
509
  .get(3)
510
510
  .value(),
@@ -5,6 +5,7 @@ const parser = require('yargs-parser');
5
5
  const unparse = require('yargs-unparser');
6
6
 
7
7
  const detox = require('../../internals');
8
+ const log = detox.log.child({ cat: ['lifecycle', 'cli'] });
8
9
  const { DetoxRuntimeError } = require('../../src/errors');
9
10
  const { printEnvironmentVariables, prependNodeModulesBinToPATH } = require('../../src/utils/envUtils');
10
11
  const { escapeSpaces } = require('../../src/utils/shellUtils');
@@ -45,7 +46,7 @@ class TestRunnerCommand {
45
46
  }
46
47
 
47
48
  /**
48
- * @param {Partial<Readonly<DetoxInternals.DetoxCLIConfig>>} cliConfig
49
+ * @param {Partial<Readonly<DetoxInternals.CLIConfig>>} cliConfig
49
50
  * @returns {this}
50
51
  */
51
52
  replicateCLIConfig(cliConfig) {
@@ -88,7 +89,7 @@ class TestRunnerCommand {
88
89
  try {
89
90
  if (launchError) {
90
91
  const list = this._argv._.map((file, index) => ` ${index + 1}. ${file}`).join('\n');
91
- detox.log.error({ event: 'RETRY_RUN' },
92
+ log.error(
92
93
  `There were failing tests in the following files:\n${list}\n\n` +
93
94
  'Detox CLI is going to restart the test runner with those files...\n'
94
95
  );
@@ -104,11 +105,13 @@ class TestRunnerCommand {
104
105
  throw e;
105
106
  }
106
107
 
107
- this._argv._ = testFilesToRetry.splice(0, Infinity);
108
- // @ts-ignore
109
- detox.session.testSessionIndex++; // it is always a primary context, so we can update it
108
+ if (--runsLeft > 0) {
109
+ this._argv._ = testFilesToRetry.splice(0, Infinity);
110
+ // @ts-ignore
111
+ detox.session.testSessionIndex++; // it is always a primary context, so we can update it
112
+ }
110
113
  }
111
- } while (launchError && --runsLeft > 0);
114
+ } while (launchError && runsLeft > 0);
112
115
 
113
116
  if (launchError) {
114
117
  throw launchError;
@@ -119,7 +122,7 @@ class TestRunnerCommand {
119
122
  const fullCommand = this._buildSpawnArguments().map(escapeSpaces);
120
123
  const fullCommandWithHint = printEnvironmentVariables(this._envHint) + fullCommand.join(' ');
121
124
 
122
- detox.log.info({ event: 'RUN_START', env: this._envHint }, fullCommandWithHint);
125
+ log.info({ env: this._envHint }, fullCommandWithHint);
123
126
 
124
127
  return new Promise((resolve, reject) => {
125
128
  cp.spawn(fullCommand[0], fullCommand.slice(1), {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "detox",
3
3
  "description": "E2E tests and automation for mobile",
4
- "version": "20.0.4-breaking.new-global-lifecycle.0",
4
+ "version": "20.0.7-prerelease.0",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -57,13 +57,14 @@
57
57
  "dependencies": {
58
58
  "ajv": "^8.6.3",
59
59
  "bunyan": "^1.8.12",
60
- "bunyan-debug-stream": "^3.0.2",
60
+ "bunyan-debug-stream": "^3.1.0",
61
61
  "chalk": "^2.4.2",
62
62
  "child-process-promise": "^2.2.0",
63
63
  "duplexify": "^4.1.2",
64
64
  "find-up": "^4.1.0",
65
65
  "fs-extra": "^4.0.2",
66
66
  "funpermaproxy": "^1.0.1",
67
+ "glob": "^8.0.3",
67
68
  "ini": "^1.3.4",
68
69
  "json-cycle": "^1.3.0",
69
70
  "lodash": "^4.17.5",
@@ -83,7 +84,7 @@
83
84
  "tail": "^2.0.0",
84
85
  "telnet-client": "1.2.8",
85
86
  "tempfile": "^2.0.0",
86
- "trace-event-lib": "^1.1.0",
87
+ "trace-event-lib": "^1.3.1",
87
88
  "which": "^1.3.1",
88
89
  "ws": "^7.0.0",
89
90
  "yargs": "^16.0.3",
@@ -183,5 +184,5 @@
183
184
  }
184
185
  }
185
186
  },
186
- "gitHead": "5a4d2fa00b359b139d9bda7f5128b9d75cfa838b"
187
+ "gitHead": "4b75f39310b93707f01e2bb38a4fba4d385e8acd"
187
188
  }
@@ -1 +1 @@
1
- module.exports = async () => require('../../internals').globalSetup();
1
+ module.exports = async () => require('../../internals').init({ workerId: null });
@@ -1 +1 @@
1
- module.exports = async () => require('../../internals').globalTeardown();
1
+ module.exports = async () => require('../../internals').cleanup();
@@ -1,9 +1,9 @@
1
- // @ts-nocheck
2
- const maybeNodeEnvironment = require('jest-environment-node'); // eslint-disable-line node/no-extraneous-require
1
+ const resolveFrom = require('resolve-from');
2
+ const maybeNodeEnvironment = require(resolveFrom(process.cwd(), 'jest-environment-node'));
3
+ // @ts-ignore
3
4
  const NodeEnvironment = maybeNodeEnvironment.default || maybeNodeEnvironment;
4
5
 
5
6
  const detox = require('../../../internals');
6
- const { DetoxError } = require('../../../src/errors');
7
7
  const Timer = require('../../../src/utils/Timer');
8
8
 
9
9
  const {
@@ -24,6 +24,8 @@ const SYNC_CIRCUS_EVENTS = new Set([
24
24
  'error',
25
25
  ]);
26
26
 
27
+ const log = detox.log.child({ cat: 'lifecycle,jest-environment' });
28
+
27
29
  /**
28
30
  * @see https://www.npmjs.com/package/jest-circus#overview
29
31
  */
@@ -41,18 +43,31 @@ class DetoxCircusEnvironment extends NodeEnvironment {
41
43
  SpecReporter,
42
44
  WorkerAssignReporter,
43
45
  };
44
- /** @protected */
46
+ /** @private */
47
+ this._shouldManageDetox = detox.getStatus() === 'inactive';
48
+ /** @internal */
45
49
  this.testPath = context.testPath;
46
50
  /** @protected */
47
51
  this.testEventListeners = [];
48
52
  /** @protected */
49
53
  this.initTimeout = detox.config.testRunner.jest.initTimeout;
54
+ /** @internal */
55
+ log.trace.begin(this.testPath);
56
+
57
+ this.setup = log.trace.complete.bind(null, 'set up environment', this.setup.bind(this));
58
+ const _teardown = this.teardown.bind(this);
59
+ this.teardown = async () => {
60
+ try {
61
+ await log.trace.complete('tear down environment', _teardown);
62
+ } finally {
63
+ await log.trace.end();
64
+ }
65
+ };
50
66
  }
51
67
 
52
68
  /** @override */
53
69
  async setup() {
54
70
  await super.setup();
55
-
56
71
  await Timer.run({
57
72
  description: `setting up Detox environment`,
58
73
  timeout: this.initTimeout,
@@ -85,7 +100,7 @@ class DetoxCircusEnvironment extends NodeEnvironment {
85
100
  try {
86
101
  await this._timer.run(() => listener[name](event, state));
87
102
  } catch (listenerError) {
88
- this._logError(listenerError);
103
+ log.error(listenerError);
89
104
  break;
90
105
  }
91
106
  }
@@ -100,9 +115,7 @@ class DetoxCircusEnvironment extends NodeEnvironment {
100
115
  await Timer.run({
101
116
  description: `tearing down Detox environment`,
102
117
  timeout: this.initTimeout,
103
- fn: async () => {
104
- await this.cleanupDetox();
105
- },
118
+ fn: async () => await this.cleanupDetox(),
106
119
  });
107
120
  }
108
121
 
@@ -115,15 +128,25 @@ class DetoxCircusEnvironment extends NodeEnvironment {
115
128
  * @protected
116
129
  */
117
130
  async initDetox() {
118
- await detox.setup({
131
+ const opts = {
119
132
  global: this.global,
120
- workerId: +process.env.JEST_WORKER_ID,
121
- });
133
+ workerId: `w${process.env.JEST_WORKER_ID}`,
134
+ };
135
+
136
+ if (this._shouldManageDetox) {
137
+ await detox.init(opts);
138
+ } else {
139
+ await detox.installWorker(opts);
140
+ }
122
141
  }
123
142
 
124
143
  /** @protected */
125
144
  async cleanupDetox() {
126
- await detox.teardown();
145
+ if (this._shouldManageDetox) {
146
+ await detox.cleanup();
147
+ } else {
148
+ await detox.uninstallWorker();
149
+ }
127
150
  }
128
151
 
129
152
  /** @private */
@@ -145,11 +168,6 @@ class DetoxCircusEnvironment extends NodeEnvironment {
145
168
  }));
146
169
  }
147
170
  }
148
-
149
- /** @private */
150
- _logError(e) {
151
- detox.log.error(DetoxError.format(e));
152
- }
153
171
  }
154
172
 
155
173
  module.exports = DetoxCircusEnvironment;
@@ -7,6 +7,8 @@ const { getFullTestName, hasTimedOut } = require('../utils');
7
7
 
8
8
  const RETRY_TIMES = Symbol.for('RETRY_TIMES');
9
9
 
10
+ const log = detoxInternals.log.child({ cat: 'lifecycle,jest-environment' });
11
+
10
12
  class DetoxCoreListener {
11
13
  constructor({ env }) {
12
14
  this._startedTests = new WeakSet();
@@ -15,11 +17,6 @@ class DetoxCoreListener {
15
17
  this._testRunTimes = 1;
16
18
  }
17
19
 
18
- _getTestInvocations(test) {
19
- const { testSessionIndex } = detoxInternals.session;
20
- return testSessionIndex * this._testRunTimes + test.invocations;
21
- }
22
-
23
20
  async setup() {
24
21
  // Workaround to override Jest's expect
25
22
  if (detoxInternals.config.behavior.init.exposeGlobals) {
@@ -27,15 +24,19 @@ class DetoxCoreListener {
27
24
  }
28
25
  }
29
26
 
30
- async run_describe_start({ describeBlock: { name, children } }) {
31
- if (children.length) {
32
- await detoxInternals.onRunDescribeStart({ name });
27
+ async run_describe_start({ describeBlock }) {
28
+ if (describeBlock.children.length) {
29
+ log.trace.begin(describeBlock.parent ? describeBlock.name : 'run the tests');
30
+ await detoxInternals.onRunDescribeStart({
31
+ name: describeBlock.name,
32
+ });
33
33
  }
34
34
  }
35
35
 
36
- async run_describe_finish({ describeBlock: { name, children } }) {
37
- if (children.length) {
38
- await detoxInternals.onRunDescribeFinish({ name });
36
+ async run_describe_finish({ describeBlock }) {
37
+ if (describeBlock.children.length) {
38
+ await detoxInternals.onRunDescribeFinish({ name: describeBlock.name });
39
+ log.trace.end();
39
40
  }
40
41
  }
41
42
 
@@ -48,61 +49,87 @@ class DetoxCoreListener {
48
49
  this._testRunTimes = isNaN(circusRetryTimes) ? 1 : 1 + circusRetryTimes;
49
50
  }
50
51
 
51
- async hook_start(_event, state) {
52
+ async hook_start(event, state) {
52
53
  await this._onBeforeActualTestStart(state.currentlyRunningTest);
54
+ log.trace.begin({ functionCode: event.hook.fn.toString() }, event.hook.type);
55
+ }
56
+
57
+ async hook_success() {
58
+ log.trace.end({ success: true });
53
59
  }
54
60
 
55
- async hook_failure({ error, hook }) {
56
- await detoxInternals.onHookFailure({
57
- error,
58
- hook: hook.type,
59
- });
61
+ async hook_failure({ error }) {
62
+ log.trace.end({ success: false, error });
60
63
  }
61
64
 
62
65
  async test_fn_start({ test }) {
63
66
  await this._onBeforeActualTestStart(test);
67
+ log.trace.begin({ functionCode: test.fn.toString() }, 'test_fn');
64
68
  }
65
69
 
66
- async test_fn_failure({ error }) {
67
- await detoxInternals.onTestFnFailure({ error });
70
+ async test_fn_success() {
71
+ log.trace.end({ success: true });
68
72
  }
69
73
 
70
- async _onBeforeActualTestStart(test) {
71
- if (!test || test.status === 'skip' || this._startedTests.has(test) || this._testsFailedBeforeStart.has(test)) {
72
- return;
73
- }
74
-
75
- this._startedTests.add(test);
76
-
77
- await detoxInternals.onTestStart({
78
- title: test.name,
79
- fullName: getFullTestName(test),
80
- status: 'running',
81
- invocations: this._getTestInvocations(test),
82
- });
74
+ async test_fn_failure({ error }) {
75
+ await detoxInternals.onTestFnFailure({ error });
76
+ log.trace.end({ success: false, error });
83
77
  }
84
78
 
85
79
  async test_done({ test }) {
86
80
  if (this._startedTests.has(test)) {
87
- await detoxInternals.onTestDone({
88
- title: test.name,
89
- fullName: getFullTestName(test),
90
- status: test.errors.length ? 'failed' : 'passed',
91
- invocations: this._getTestInvocations(test),
92
- timedOut: hasTimedOut(test)
93
- });
94
-
81
+ const failed = test.errors.length > 0;
82
+ const metadata = {
83
+ ...this._getTestMetadata(test),
84
+ status: failed ? 'failed' : 'passed',
85
+ timedOut: failed ? hasTimedOut(test) : undefined,
86
+ };
87
+
88
+ await detoxInternals.onTestDone(metadata);
95
89
  this._startedTests.delete(test);
90
+ log.trace.end({
91
+ status: metadata.status,
92
+ timedOut: metadata.timedOut,
93
+ });
96
94
  }
97
95
  }
98
96
 
99
97
  async run_finish(_event, state) {
100
- if (this._hasFailedTests(state.rootDescribeBlock)) {
98
+ const hasFailedTests = this._hasFailedTests(state.rootDescribeBlock);
99
+ if (hasFailedTests) {
101
100
  const handledByJestCircus = this._testRunTimes > 1 && !detoxInternals.config.testRunner.jest.retryAfterCircusRetries;
102
101
  await detoxInternals.reportFailedTests([this._env.testPath], handledByJestCircus);
103
102
  }
104
103
  }
105
104
 
105
+ async _onBeforeActualTestStart(test) {
106
+ if (!test || test.status === 'skip' || this._startedTests.has(test) || this._testsFailedBeforeStart.has(test)) {
107
+ return false;
108
+ }
109
+
110
+ const metadata = {
111
+ ...this._getTestMetadata(test),
112
+ status: 'running',
113
+ };
114
+
115
+ this._startedTests.add(test);
116
+
117
+ log.trace.begin({
118
+ context: 'test',
119
+ status: metadata.status,
120
+ fullName: metadata.fullName,
121
+ invocations: metadata.invocations,
122
+ }, metadata.title);
123
+
124
+ await detoxInternals.onTestStart(metadata);
125
+ return true;
126
+ }
127
+
128
+ _getTestInvocations(test) {
129
+ const { testSessionIndex } = detoxInternals.session;
130
+ return testSessionIndex * this._testRunTimes + test.invocations;
131
+ }
132
+
106
133
  _hasFailedTests(block) {
107
134
  if (block.children) {
108
135
  for (const child of block.children) {
@@ -114,6 +141,14 @@ class DetoxCoreListener {
114
141
 
115
142
  return block.errors ? block.errors.length > 0 : false;
116
143
  }
144
+
145
+ _getTestMetadata(test) {
146
+ return {
147
+ title: test.name,
148
+ fullName: getFullTestName(test),
149
+ invocations: this._getTestInvocations(test),
150
+ };
151
+ }
117
152
  }
118
153
 
119
154
  module.exports = DetoxCoreListener;
@@ -118,7 +118,7 @@ class SpecReporter {
118
118
  const retriesDescription = (invocations > 1) ? chalk.gray(` [Retry #${invocations - 1}]`) : '';
119
119
  const status = chalk.gray(_status ? ` [${_status}]` : '');
120
120
  const desc = this._suitesDesc + testDescription + retriesDescription + status;
121
- log.info({ event: 'SPEC_STATE_CHANGE' }, desc);
121
+ log.info({ cat: 'lifecycle' }, desc);
122
122
  }
123
123
  }
124
124
 
@@ -13,7 +13,7 @@ class WorkerAssignReporter {
13
13
 
14
14
  run_start() {
15
15
  if (config.testRunner.jest.reportWorkerAssign) {
16
- log.info({ event: 'WORKER_ASSIGN' }, `${this._formatTestName()} is assigned to ${this._formatDeviceName()}`);
16
+ log.info({ cat: 'lifecycle' }, `${this._formatTestName()} is assigned to ${this._formatDeviceName()}`);
17
17
  }
18
18
  }
19
19
 
@@ -32,6 +32,8 @@ class DetoxWorker {
32
32
  onError: this._onEmitError.bind(this),
33
33
  });
34
34
 
35
+ /** @type {string} */
36
+ this.id = 'worker';
35
37
  /** @type {Detox.Device} */
36
38
  this.device = null;
37
39
  /** @type {Detox.ElementFacade} */
@@ -63,14 +65,15 @@ class DetoxWorker {
63
65
  device: deviceConfig,
64
66
  session: sessionConfig
65
67
  } = this._config;
68
+
66
69
  this._appsConfig = appsConfig;
67
70
  this._artifactsConfig = artifactsConfig;
68
71
  this._behaviorConfig = behaviorConfig;
69
72
  this._deviceConfig = deviceConfig;
70
73
  this._sessionConfig = sessionConfig;
74
+ this._sessionConfig.sessionId = sessionConfig.sessionId || uuid.UUID();
71
75
  this._runtimeErrorComposer.appsConfig = this._appsConfig;
72
76
 
73
- sessionConfig.sessionId = sessionConfig.sessionId || uuid.UUID();
74
77
  this._client = new Client(sessionConfig);
75
78
  this._client.terminateApp = async () => {
76
79
  // @ts-ignore
@@ -192,7 +195,6 @@ class DetoxWorker {
192
195
  onTestStart = async (testSummary) => {
193
196
  if (this._isCleaningUp) return;
194
197
  this._validateTestSummary('beforeEach', testSummary);
195
- this._logTestRunCheckpoint('DETOX_BEFORE_EACH', testSummary);
196
198
 
197
199
  if (this._isCleaningUp) return;
198
200
  await this._dumpUnhandledErrorsIfAny({
@@ -212,7 +214,6 @@ class DetoxWorker {
212
214
  onTestDone = async (testSummary) => {
213
215
  if (this._isCleaningUp) return;
214
216
  this._validateTestSummary('afterEach', testSummary);
215
- this._logTestRunCheckpoint('DETOX_AFTER_EACH', testSummary);
216
217
 
217
218
  if (this._isCleaningUp) return;
218
219
  await this._artifactsManager.onTestDone(testSummary);
@@ -248,10 +249,6 @@ class DetoxWorker {
248
249
  }
249
250
  }
250
251
 
251
- _logTestRunCheckpoint(event, { status, fullName }) {
252
- this.log.trace({ event, status }, `${status} test: ${JSON.stringify(fullName)}`);
253
- }
254
-
255
252
  _validateTestSummary(methodName, testSummary) {
256
253
  if (!_.isPlainObject(testSummary)) {
257
254
  throw this._runtimeErrorComposer.invalidTestSummary(methodName, testSummary);