detox 20.0.14-prerelease.0 → 20.0.15-prerelease.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. package/Detox-android/com/wix/detox/{20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar → 20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar → 20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar → 20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar} +0 -0
  12. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom → 20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-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 +0 -2
  29. package/local-cli/test.test.js +47 -10
  30. package/local-cli/testCommand/TestRunnerCommand.js +4 -3
  31. package/local-cli/testCommand/middlewares.js +3 -2
  32. package/package.json +6 -14
  33. package/runners/jest/index.test.js +13 -0
  34. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +57 -34
  35. package/src/android/interactions/native.js +3 -2
  36. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +2 -0
  37. package/src/devices/runtime/RuntimeDevice.js +3 -3
  38. package/src/ios/expectTwo.js +3 -2
  39. package/src/logger/DetoxLogger.js +31 -22
  40. package/src/logger/utils/BunyanLogger.js +11 -7
  41. package/src/logger/utils/CategoryThreadDispatcher.js +1 -1
  42. package/src/logger/utils/DetoxLogFinalizer.js +11 -5
  43. package/src/logger/utils/sanitizeBunyanContext.js +3 -1
  44. package/src/logger/utils/tracerLegacy.js +14 -25
  45. package/src/utils/logger.js +1 -1
  46. package/src/utils/traceInvocationCall.js +21 -0
  47. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.md5 +0 -1
  48. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha1 +0 -1
  49. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha256 +0 -1
  50. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-javadoc.jar.sha512 +0 -1
  51. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.md5 +0 -1
  52. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha1 +0 -1
  53. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha256 +0 -1
  54. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0-sources.jar.sha512 +0 -1
  55. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.md5 +0 -1
  56. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha1 +0 -1
  57. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha256 +0 -1
  58. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.aar.sha512 +0 -1
  59. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.md5 +0 -1
  60. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.sha1 +0 -1
  61. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.sha256 +0 -1
  62. package/Detox-android/com/wix/detox/20.0.14-prerelease.0/detox-20.0.14-prerelease.0.pom.sha512 +0 -1
  63. package/src/utils/trace.js +0 -3
@@ -0,0 +1 @@
1
+ 3d69a7ece65dfc290ba7c7a71d7e76227353d86f
@@ -0,0 +1 @@
1
+ d34810beb66a73776549bfa5f5c2eefc40250584f69bf471612403f18ea8b518
@@ -0,0 +1 @@
1
+ c59585aa86f4995c6873ae6fc086b882076b6c3a655388515abcacbadb3dbddd46712869703619e903dff89c466ed080634e113b3a480465fa27ec3edde08d7a
@@ -0,0 +1 @@
1
+ 8cc49ca4de60598d65767133544f0bd6ad97b494
@@ -0,0 +1 @@
1
+ 5ad08ad6fb9c09f1391a326d24d96b939ca8cde038f78dbc7ff0a4604e27f3b0
@@ -0,0 +1 @@
1
+ 403e4e5b90acce7b564bb73213361df77e3e226a36465c7308875a7511e6c8794ab22c8cbd3580eb439798b0245d4a54be94e818a08ffa5125bc85913e802f94
@@ -0,0 +1 @@
1
+ 3bdd1b42fa0f182255a47fcdda8f544c
@@ -0,0 +1 @@
1
+ 457ae10d202b196ea92bade4a33ce2dbc2f8bb3f
@@ -0,0 +1 @@
1
+ 52342d1b0d1fae681b2ea1e6f9ac6f6278299ed70d7867fd60b95d63eb7a9ec3
@@ -0,0 +1 @@
1
+ 5dfa73d84d647fd870a2e915d9943c9502c967abfd89a834ef7dee50a2a77d5a8b0be7b13407a34a6b97cbc10e9ed6f5e608fe7366d5a3041e462e3322d5b10d
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox</artifactId>
6
- <version>20.0.14-prerelease.0</version>
6
+ <version>20.0.15-prerelease.0</version>
7
7
  <packaging>aar</packaging>
8
8
  <name>Detox</name>
9
9
  <description>Gray box end-to-end testing and automation library for mobile apps</description>
@@ -0,0 +1 @@
1
+ 8c1df15d68775116019b04b9496a6ff6
@@ -0,0 +1 @@
1
+ dbe3d335c31886336e6c969b38e222d6f92004da
@@ -0,0 +1 @@
1
+ 4ec36429edce121f9a29981a67b9ea84bce00e7c4991bd6d1636c8edb0d3b322
@@ -0,0 +1 @@
1
+ c4b645ab10c009733624a5aebb04c701a0b73e22dc419b3ba5a396d6937bad9d26e1ae7d9c4057bfc5d915b4af91250af6c5b991535b8554ba1d80abb3990b10
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.0.14-prerelease.0</latest>
7
- <release>20.0.14-prerelease.0</release>
6
+ <latest>20.0.15-prerelease.0</latest>
7
+ <release>20.0.15-prerelease.0</release>
8
8
  <versions>
9
- <version>20.0.14-prerelease.0</version>
9
+ <version>20.0.15-prerelease.0</version>
10
10
  </versions>
11
- <lastUpdated>20221108145605</lastUpdated>
11
+ <lastUpdated>20221110171141</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- ba7d8cb5496d1d9366a8234bc4e64055
1
+ 0a8740dfdf732622e512707d164837bc
@@ -1 +1 @@
1
- 77f004770bdd78a7442584a10dd84ef431783841
1
+ f892f8ff0cda46b0e16a893224d340c1e3d2c803
@@ -1 +1 @@
1
- dd9c1791bb2c603c4806ebca0b071f52229edadedc9e487d52a434c1c24638b7
1
+ 9ed56153c167d071db724c68d6e141358916df50340cf29bb3ff23ea8db43091
@@ -1 +1 @@
1
- a2914ac9dc6c4bd7a1f84a46a8f84e467d314b71f96d6603c4303bc54344d354fdc2903e1934c275ee785cd4a544c7a7f575c512ad6b623b76f943b672be718c
1
+ 13e2b660cbe1403226c025fe83ebb5f8c9f28de41fd432bcc355a9b42562e9158e68c161b6cf801f45c9878565d46beb7884b5b62d6ace714e36d06d17a1d1e3
package/Detox-ios-src.tbz CHANGED
Binary file
package/Detox-ios.tbz CHANGED
Binary file
package/index.d.ts CHANGED
@@ -472,8 +472,6 @@ declare global {
472
472
  readonly startSection: (name: string) => void;
473
473
  /** @deprecated */
474
474
  readonly endSection: (name: string) => void;
475
- /** @private */
476
- readonly invocationCall: (...args: unknown[]) => unknown;
477
475
  };
478
476
 
479
477
  /**
@@ -108,22 +108,49 @@ describe('CLI', () => {
108
108
  ])('given no extra args (%s)', (_platform, deviceType) => {
109
109
  beforeEach(async () => {
110
110
  singleConfig().device.type = deviceType;
111
- await run();
112
111
  });
113
112
 
114
- test('should produce a default command', () => {
115
- expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
116
- });
113
+ describe('when testRunner.forwardEnv is true', () => {
114
+ beforeEach(async () => {
115
+ singleConfig().testRunner = { forwardEnv: true };
116
+ await run();
117
+ });
118
+
119
+ test('should produce a default command', () => {
120
+ expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
121
+ });
122
+
123
+ test('should override environment variables', () => {
124
+ expect(cliCall().env).toEqual({
125
+ DETOX_CONFIG_PATH: expect.any(String),
126
+ DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String)
127
+ });
128
+ });
117
129
 
118
- test('should not override environment variables', () => {
119
- expect(cliCall().env).toEqual({
120
- DETOX_CONFIG_PATH: expect.any(String),
121
- DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String)
130
+ test('should hint essential environment variables', () => {
131
+ expect(cliCall().fullCommand).toMatch(/\bDETOX_CONFIG_PATH=.*\bexecutable\b/);
122
132
  });
123
133
  });
124
134
 
125
- test('should hint essential environment variables', () => {
126
- expect(cliCall().fullCommand).toMatch(/\bDETOX_CONFIG_PATH=.*\bexecutable\b/);
135
+ describe('when testRunner.forwardEnv is false', () => {
136
+ beforeEach(async () => {
137
+ singleConfig().testRunner = { forwardEnv: false };
138
+ await run();
139
+ });
140
+
141
+ test('should produce a default command', () => {
142
+ expect(cliCall().argv).toEqual([expect.stringContaining('executable'), '--config', 'e2e/config.json']);
143
+ });
144
+
145
+ test('should not override environment variables', () => {
146
+ expect(cliCall().env).toEqual({
147
+ DETOX_CONFIG_SNAPSHOT_PATH: expect.any(String)
148
+ });
149
+ });
150
+
151
+ test('should not hint essential environment variables', () => {
152
+ expect(cliCall().fullCommand).not.toMatch(/\bDETOX_CONFIG_PATH=.*\bexecutable\b/);
153
+ });
127
154
  });
128
155
  });
129
156
 
@@ -468,6 +495,16 @@ describe('CLI', () => {
468
495
  expect(logger().warn).toHaveBeenCalledWith(expect.stringContaining('$DETOX_ARGV_OVERRIDE is detected'));
469
496
  });
470
497
 
498
+ test('should append $DETOX_ARGV_OVERRIDE "--" part to test runner command', async () => {
499
+ process.env.PLATFORM = 'ios';
500
+ process.env.DETOX_ARGV_OVERRIDE = '-- --help';
501
+
502
+ await run();
503
+
504
+ expect(cliCall().argv.slice(-1)).toEqual(['--help']);
505
+ expect(logger().warn).toHaveBeenCalledWith(expect.stringContaining('$DETOX_ARGV_OVERRIDE is detected'));
506
+ });
507
+
471
508
  // Helpers
472
509
 
473
510
  function tempfile(extension, content) {
@@ -14,7 +14,7 @@ class TestRunnerCommand {
14
14
  /*
15
15
  @param {object} opts
16
16
  @param {DetoxInternals.RuntimeConfig} opts.config
17
- @param {ProcessEnv} [opts.env]
17
+ @param {ProcessEnv} opts.env
18
18
  */
19
19
  constructor(opts) {
20
20
  const cliConfig = opts.config.cli;
@@ -68,7 +68,7 @@ class TestRunnerCommand {
68
68
  }
69
69
  }
70
70
 
71
- _buildEnvHint(env = process.env) {
71
+ _buildEnvHint(env) {
72
72
  return _(env)
73
73
  .mapKeys((_value, key) => key.toUpperCase())
74
74
  .pickBy((_value, key) => key.startsWith('DETOX_'))
@@ -127,7 +127,7 @@ class TestRunnerCommand {
127
127
  .tap(prependNodeModulesBinToPATH)
128
128
  .value()
129
129
  })
130
- .on('error', (err) => reject(err))
130
+ .on('error', /* istanbul ignore next */ (err) => reject(err))
131
131
  .on('exit', (code) => code === 0
132
132
  ? resolve()
133
133
  : reject(new DetoxRuntimeError(`Command failed with exit code = ${code}:\n${fullCommandWithHint}`)
@@ -136,6 +136,7 @@ class TestRunnerCommand {
136
136
  }
137
137
 
138
138
  _buildSpawnArguments() {
139
+ /* istanbul ignore next */
139
140
  const { _: specs = [], '--': passthrough = [], $0, ...argv } = this._argv;
140
141
  const { _: $0_, ...$0argv } = parser($0);
141
142
 
@@ -13,12 +13,13 @@ function applyEnvironmentVariableAddendum(argv, yargs) {
13
13
 
14
14
  const { _: positional, '--': passthrough, ...named } = yargs.parse(process.env.DETOX_ARGV_OVERRIDE);
15
15
 
16
- if (positional) {
16
+ if (!_.isEmpty(positional)) {
17
+ /* istanbul ignore next */
17
18
  argv._ = argv._ || [];
18
19
  argv._.push(...positional.map(simpleUnquote));
19
20
  }
20
21
 
21
- if (passthrough) {
22
+ if (!_.isEmpty(passthrough)) {
22
23
  argv['--'] = argv['--'] || [];
23
24
  argv['--'].push(...passthrough.map(simpleUnquote));
24
25
  }
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.14-prerelease.0",
4
+ "version": "20.0.15-prerelease.0",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -160,20 +160,12 @@
160
160
  "src/utils/pipeCommands.js",
161
161
  "src/utils/pressAnyKey.js",
162
162
  "src/utils/shellUtils.js",
163
- "local-cli/testCommand/TestRunnerCommand.js",
164
- "local-cli/testCommand/middlewares.js",
163
+ "runners/jest/reporters",
164
+ "runners/jest/testEnvironment",
165
165
  "src/DetoxWorker.js",
166
- "src/artifacts/ArtifactsManager.js",
167
- "src/devices/lifecycle/GenyGlobalLifecycleHandler.js",
168
- "src/errors/DetoxError.js",
166
+ "src/logger/utils/streamUtils.js",
169
167
  "src/ipc",
170
- "src/logger",
171
- "src/realms",
172
- "src/utils/Timer.js",
173
- "src/utils/envUtils.js",
174
- "runners/jest/index.js",
175
- "runners/jest/reporters",
176
- "runners/jest/testEnvironment"
168
+ "src/realms"
177
169
  ],
178
170
  "resetMocks": true,
179
171
  "resetModules": true,
@@ -198,5 +190,5 @@
198
190
  }
199
191
  }
200
192
  },
201
- "gitHead": "40d0a32720bb36575136f3c2769407bb2cef0cdf"
193
+ "gitHead": "5bfd04ef867767c3eb9690c418bf80588d367d3e"
202
194
  }
@@ -0,0 +1,13 @@
1
+ describe('detox/runners/jest', () => {
2
+ it('should lazily require the exported modules', () => {
3
+ const index = require('./index');
4
+
5
+ jest.mock('./testEnvironment', () => 0);
6
+ jest.mock('./globalSetup', () => 1);
7
+ jest.mock('./globalTeardown', () => 2);
8
+
9
+ expect(index.DetoxCircusEnvironment).toBe(0);
10
+ expect(index.globalSetup).toBe(1);
11
+ expect(index.globalTeardown).toBe(2);
12
+ });
13
+ });
@@ -41,10 +41,22 @@ class DetoxCoreListener {
41
41
  }
42
42
 
43
43
  async test_start({ test }) {
44
- if (!_.isEmpty(test.errors)) {
44
+ const metadata = this._getTestMetadata(test);
45
+ if (metadata.status === 'failed') {
45
46
  this._testsFailedBeforeStart.add(test);
46
47
  }
47
48
 
49
+ const logTrace = this._isTestSkipped(test)
50
+ ? log.trace
51
+ : log.trace.begin;
52
+
53
+ logTrace({
54
+ context: 'test',
55
+ status: metadata.status,
56
+ fullName: metadata.fullName,
57
+ invocations: metadata.invocations,
58
+ }, metadata.title);
59
+
48
60
  const circusRetryTimes = +this._env.global[RETRY_TIMES];
49
61
  this._circusRetryTimes = isNaN(circusRetryTimes) ? 1 : 1 + circusRetryTimes;
50
62
  }
@@ -69,7 +81,11 @@ class DetoxCoreListener {
69
81
 
70
82
  async test_fn_start({ test }) {
71
83
  await this._onBeforeActualTestStart(test);
72
- log.trace.begin({ functionCode: test.fn.toString() }, 'test_fn');
84
+
85
+ if (!this._testsFailedBeforeStart.has(test)) {
86
+ // Jest bug workaround: beforeAll hook errors result into an unterminated test_fn_start event.
87
+ log.trace.begin({ functionCode: test.fn.toString() }, 'test_fn');
88
+ }
73
89
  }
74
90
 
75
91
  async test_fn_success() {
@@ -82,61 +98,68 @@ class DetoxCoreListener {
82
98
  }
83
99
 
84
100
  async test_done({ test }) {
85
- if (this._startedTests.has(test)) {
86
- const failed = test.errors.length > 0;
87
- const metadata = {
88
- ...this._getTestMetadata(test),
89
- status: failed ? 'failed' : 'passed',
90
- timedOut: failed ? hasTimedOut(test) : undefined,
91
- };
101
+ const metadata = this._getTestMetadata(test);
92
102
 
103
+ if (this._startedTests.has(test)) {
93
104
  await detoxInternals.onTestDone(metadata);
94
105
  this._startedTests.delete(test);
95
- log.trace.end({
96
- status: metadata.status,
97
- timedOut: metadata.timedOut,
98
- });
99
106
  }
107
+
108
+ log.trace.end(_.pick(metadata, ['status', 'timedOut']));
100
109
  }
101
110
 
102
111
  async _onBeforeActualTestStart(test) {
103
112
  if (!this._isTestActuallyStarting(test)) {
104
- return false;
113
+ return;
105
114
  }
106
115
 
107
- const metadata = {
108
- ...this._getTestMetadata(test),
109
- status: 'running',
110
- };
111
-
112
116
  this._startedTests.add(test);
113
-
114
- log.trace.begin({
115
- context: 'test',
116
- status: metadata.status,
117
- fullName: metadata.fullName,
118
- invocations: metadata.invocations,
119
- }, metadata.title);
120
-
121
- await detoxInternals.onTestStart(metadata);
122
- return true;
117
+ await detoxInternals.onTestStart(this._getTestMetadata(test));
123
118
  }
124
119
 
125
120
  _isTestActuallyStarting(test) {
126
- return test && test.status !== 'skip' && !this._startedTests.has(test) && !this._testsFailedBeforeStart.has(test);
121
+ return test && !this._isTestSkipped(test) && !this._startedTests.has(test) && !this._testsFailedBeforeStart.has(test);
127
122
  }
128
123
 
129
- _getTestInvocations(test) {
130
- const { testSessionIndex } = detoxInternals.session;
131
- return testSessionIndex * this._circusRetryTimes + test.invocations;
124
+ _isTestSkipped(test) {
125
+ return test && (test.mode === 'skip' || test.mode === 'todo');
132
126
  }
133
127
 
134
128
  _getTestMetadata(test) {
135
- return {
129
+ const result = {
136
130
  title: test.name,
137
131
  fullName: getFullTestName(test),
132
+ status: this._getTestStatus(test),
138
133
  invocations: this._getTestInvocations(test),
139
134
  };
135
+
136
+ if (result.status === 'failed') {
137
+ result.timedOut = hasTimedOut(test);
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ /** @returns { 'failed' | 'passed' | 'running' | 'skip' | 'todo' } */
144
+ _getTestStatus(test) {
145
+ if (!_.isEmpty(test.errors)) {
146
+ return 'failed';
147
+ }
148
+
149
+ if (this._isTestSkipped(test)) {
150
+ return test.mode;
151
+ }
152
+
153
+ if (test.status === 'done') {
154
+ return 'passed';
155
+ } else {
156
+ return test.status || 'running';
157
+ }
158
+ }
159
+
160
+ _getTestInvocations(test) {
161
+ const { testSessionIndex } = detoxInternals.session;
162
+ return testSessionIndex * this._circusRetryTimes + test.invocations;
140
163
  }
141
164
  }
142
165
 
@@ -1,6 +1,7 @@
1
1
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
2
2
  const { expectDescription, actionDescription } = require('../../utils/invocationTraceDescriptions');
3
- const { trace } = require('../../utils/trace');
3
+ const log = require('../../utils/logger').child({ cat: 'ws-client, ws' });
4
+ const traceInvocationCall = require('../../utils/traceInvocationCall').bind(null, log);
4
5
  const { ScrollAmountStopAtEdgeAction } = require('../actions/native');
5
6
  const { NativeMatcher } = require('../core/NativeMatcher');
6
7
  const DetoxAssertionApi = require('../espressoapi/DetoxAssertion');
@@ -18,7 +19,7 @@ class Interaction {
18
19
  }
19
20
 
20
21
  async execute() {
21
- return trace.invocationCall(this._traceDescription, this._call,
22
+ return traceInvocationCall(this._traceDescription, this._call,
22
23
  this._invocationManager.execute(this._call).then((resultObj) => resultObj ? resultObj.result : undefined));
23
24
  }
24
25
  }
@@ -10,6 +10,8 @@ class GenyGlobalLifecycleHandler {
10
10
  this._instanceLifecycleService = instanceLifecycleService;
11
11
  }
12
12
 
13
+ // TODO: remove this ignore as soon as DetoxPrimaryContext is covered with tests
14
+ /* istanbul ignore next */
13
15
  async globalInit() {}
14
16
 
15
17
  emergencyCleanup() {
@@ -1,7 +1,6 @@
1
1
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
2
2
  const debug = require('../../utils/debug'); // debug utils, leave here even if unused
3
3
  const log = require('../../utils/logger').child({ cat: 'device' });
4
- const { traceCall } = require('../../utils/trace');
5
4
  const traceMethods = require('../../utils/traceMethods');
6
5
  const wrapWithStackTraceCutter = require('../../utils/wrapWithStackTraceCutter');
7
6
 
@@ -22,6 +21,7 @@ class RuntimeDevice {
22
21
  'disableSynchronization',
23
22
  'enableSynchronization',
24
23
  'installApp',
24
+ 'installUtilBinaries',
25
25
  'launchApp',
26
26
  'matchFace',
27
27
  'matchFinger',
@@ -258,12 +258,12 @@ class RuntimeDevice {
258
258
  async installUtilBinaries() {
259
259
  const paths = this._deviceConfig.utilBinaryPaths;
260
260
  if (paths) {
261
- await traceCall('installUtilBinaries', this.deviceDriver.installUtilBinaries(paths));
261
+ await this.deviceDriver.installUtilBinaries(paths);
262
262
  }
263
263
  }
264
264
 
265
265
  async reloadReactNative() {
266
- await traceCall('reload React Native', this.deviceDriver.reloadReactNative());
266
+ await this.deviceDriver.reloadReactNative();
267
267
  }
268
268
 
269
269
  async openURL(params) {
@@ -8,7 +8,8 @@ const tempfile = require('tempfile');
8
8
 
9
9
  const { assertEnum, assertNormalized } = require('../utils/assertArgument');
10
10
  const { actionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
11
- const { trace } = require('../utils/trace');
11
+ const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
12
+ const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);
12
13
 
13
14
  const assertDirection = assertEnum(['left', 'right', 'up', 'down']);
14
15
  const assertSpeed = assertEnum(['fast', 'slow']);
@@ -747,7 +748,7 @@ function throwElementError(param) {
747
748
  }
748
749
 
749
750
  function _executeInvocation(invocationManager, invocation, traceDescription) {
750
- return trace.invocationCall(traceDescription, invocation, invocationManager.execute(invocation));
751
+ return traceInvocationCall(traceDescription, invocation, invocationManager.execute(invocation));
751
752
  }
752
753
 
753
754
  module.exports = IosExpect;
@@ -2,7 +2,6 @@ const path = require('path');
2
2
 
3
3
  const _ = require('lodash');
4
4
 
5
- const temporaryPath = require('../artifacts/utils/temporaryPath');
6
5
  const { DetoxInternalError, DetoxError } = require('../errors');
7
6
  const { shortFormat } = require('../utils/dateUtils');
8
7
  const isPromise = require('../utils/isPromise');
@@ -16,7 +15,7 @@ const sanitizeBunyanContext = require('./utils/sanitizeBunyanContext');
16
15
  /**
17
16
  * @typedef SharedLoggerConfig
18
17
  * @property {string} file
19
- * @property {Detox.DetoxLoggerConfig} userConfig
18
+ * @property {Detox.DetoxLoggerConfig} [userConfig]
20
19
  * @property {CategoryThreadDispatcher} [dispatcher]
21
20
  * @property {BunyanLogger} [bunyan]
22
21
  * @property {MessageStack} [messageStack]
@@ -92,7 +91,7 @@ class DetoxLogger {
92
91
  * @returns {DetoxLogger}
93
92
  */
94
93
  child(overrides) {
95
- const merged = this._mergeContexts(this._context, overrides);
94
+ const merged = this._mergeContexts(this._context, sanitizeBunyanContext(overrides));
96
95
  return new DetoxLogger(this._sharedConfig, merged);
97
96
  }
98
97
 
@@ -116,7 +115,6 @@ class DetoxLogger {
116
115
  }
117
116
 
118
117
  _.merge(this.config, config);
119
- this._sharedConfig.file = temporaryPath.for.jsonl();
120
118
  this._sharedConfig.bunyan.installDebugStream(this.config);
121
119
  this.overrideConsole();
122
120
  }
@@ -138,14 +136,23 @@ class DetoxLogger {
138
136
  */
139
137
  _mergeContexts(...contexts) {
140
138
  const context = Object.assign({}, ...contexts);
139
+ const categories = _(contexts).flatMap((c) => {
140
+ if (c && c.cat) {
141
+ return _.isArray(c.cat) ? c.cat : c.cat.split(',');
142
+ }
143
+
144
+ return [];
145
+ }).uniq().join(',');
141
146
 
142
147
  if (context.error || context.err) {
143
148
  context.error = DetoxError.format(context.error || context.err);
144
149
  delete context.err;
145
150
  }
146
151
 
147
- if (Array.isArray(context.cat)) {
148
- context.cat = context.cat.join(',');
152
+ if (categories) {
153
+ context.cat = categories;
154
+ } else {
155
+ delete context.cat;
149
156
  }
150
157
 
151
158
  if (context.__filename) {
@@ -153,15 +160,13 @@ class DetoxLogger {
153
160
  }
154
161
 
155
162
  context.ph = context.ph || 'i';
156
- context.cat = context.cat || '';
157
-
158
163
  context.tid = this._sharedConfig.dispatcher.resolve(
159
164
  context.ph,
160
165
  context.cat,
161
166
  context.id || 0
162
167
  );
163
168
 
164
- return sanitizeBunyanContext(context);
169
+ return context;
165
170
  }
166
171
 
167
172
  /**
@@ -182,6 +187,11 @@ class DetoxLogger {
182
187
  /** @private */
183
188
  _begin(level, ...args) {
184
189
  const { context, msg } = this._parseArgs({ ph: 'B' }, args);
190
+ this._beginInternal(level, context, msg);
191
+ }
192
+
193
+ /** @private */
194
+ _beginInternal(level, context, msg) {
185
195
  this._sharedConfig.messageStack.push(context.tid, msg);
186
196
  this._sharedConfig.bunyan.logger[level](context, ...msg);
187
197
  }
@@ -189,8 +199,14 @@ class DetoxLogger {
189
199
  /** @private */
190
200
  _end(level, ...args) {
191
201
  let { context, msg } = this._parseArgs({ ph: 'E' }, args);
202
+ this._endInternal(level, context, msg);
203
+ }
204
+
205
+ /** @private */
206
+ _endInternal(level, context, msg) {
207
+ const beginMsg = this._sharedConfig.messageStack.pop(context.tid);
192
208
  if (msg.length === 0) {
193
- msg = this._sharedConfig.messageStack.pop(context.tid);
209
+ msg = beginMsg;
194
210
  }
195
211
 
196
212
  this._sharedConfig.bunyan.logger[level](context, ...msg);
@@ -221,14 +237,14 @@ class DetoxLogger {
221
237
  });
222
238
 
223
239
  let result;
224
- this[level].begin(context, ...msg);
240
+ this._beginInternal(level, { ...context, ph: 'B' }, msg);
225
241
  try {
226
242
  result = typeof action === 'function'
227
243
  ? action()
228
244
  : action;
229
245
 
230
246
  if (!isPromise(result)) {
231
- end(context);
247
+ end({ success: true });
232
248
  } else {
233
249
  result.then(
234
250
  () => end({ success: true }),
@@ -250,20 +266,13 @@ class DetoxLogger {
250
266
  : _.isObject(args[0])
251
267
  ? args[0]
252
268
  : undefined;
253
- const msg = userContext !== undefined ? args.slice(1) : args;
254
269
 
255
- if (userContext) {
256
- delete userContext.pid;
257
- delete userContext.tid;
258
- delete userContext.ts;
259
- delete userContext.time;
260
- delete userContext.ph;
261
- }
270
+ const msg = userContext !== undefined ? args.slice(1) : args;
262
271
 
263
272
  const context = this._mergeContexts(
264
273
  this._context,
265
274
  boundContext,
266
- userContext,
275
+ sanitizeBunyanContext(userContext),
267
276
  );
268
277
 
269
278
  return { context, msg };
@@ -280,7 +289,7 @@ class DetoxLogger {
280
289
  : undefined;
281
290
 
282
291
  const cat = level === 'trace' || level === 'debug'
283
- ? (value) => require('chalk').yellow((value || '').split(',', 1)[0])
292
+ ? (value) => require('chalk').yellow(`${value}`.split(',', 1)[0])
284
293
  : undefined;
285
294
 
286
295
  const event = level === 'trace' || level === 'debug'
@@ -27,8 +27,6 @@ class BunyanLogger {
27
27
  * @returns {this}
28
28
  */
29
29
  installDebugStream(config) {
30
- const level = config.level || 'info';
31
-
32
30
  if (this._debugStream) {
33
31
  _.remove(this._bunyan['streams'], this._debugStream);
34
32
  // @ts-ignore
@@ -36,13 +34,17 @@ class BunyanLogger {
36
34
  this._debugStream = null;
37
35
  }
38
36
 
37
+ const streamOptions = { out: null, ...config.options };
38
+ /* istanbul ignore next */
39
+ if (!streamOptions.out) {
40
+ // This is a default if-else branch, used everywhere except for the unit tests.
41
+ streamOptions.out = new PassThrough().pipe(process.stderr);
42
+ }
43
+
39
44
  this._debugStream = {
40
45
  type: 'raw',
41
- level,
42
- stream: bds.default({
43
- ...config.options,
44
- out: new PassThrough().pipe(process.stderr),
45
- }),
46
+ level: config.level,
47
+ stream: bds.default(streamOptions),
46
48
  };
47
49
 
48
50
  this._bunyan.addStream(this._debugStream);
@@ -54,7 +56,9 @@ class BunyanLogger {
54
56
  * @returns {this}
55
57
  */
56
58
  installFileStream(file) {
59
+ /* istanbul ignore next */
57
60
  if (this._fileStream) {
61
+ // This is an impossible condition, but we keep it here for the sake of completeness.
58
62
  throw new DetoxInternalError('Trying to install a second file stream inside already initialized Bunyan logger');
59
63
  }
60
64
 
@@ -24,7 +24,7 @@ class CategoryThreadDispatcher {
24
24
 
25
25
  /** @returns {ThreadDispatcher} */
26
26
  _resolveDispatcher(cat) {
27
- const mainCategory = cat ? cat.split(',', 1)[0] : 'default';
27
+ const mainCategory = cat ? cat.split(',', 1)[0] : 'undefined';
28
28
  if (!this._dispatchers[mainCategory]) {
29
29
  this._dispatchers[mainCategory] = new ThreadDispatcher(mainCategory);
30
30
  }
@@ -59,15 +59,17 @@ class DetoxLogFinalizer {
59
59
 
60
60
  finalizeSync() {
61
61
  const sessionId = this._session.id;
62
- const rootDir = this._config.artifacts.rootDir;
63
- const logsEnabled = this._areLogsEnabled();
62
+ const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
63
+ if (logs.length === 0) {
64
+ return;
65
+ }
64
66
 
67
+ const logsEnabled = this._areLogsEnabled();
68
+ const rootDir = logsEnabled ? this._config.artifacts.rootDir : '';
65
69
  if (logsEnabled) {
66
70
  fs.mkdirpSync(rootDir);
67
71
  }
68
72
 
69
- const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
70
-
71
73
  for (const log of logs) {
72
74
  if (logsEnabled) {
73
75
  fs.moveSync(log, path.join(rootDir, path.basename(log)));
@@ -85,6 +87,10 @@ class DetoxLogFinalizer {
85
87
 
86
88
  /** @private */
87
89
  _areLogsEnabled() {
90
+ if (!this._config) {
91
+ return false;
92
+ }
93
+
88
94
  const { rootDir, plugins } = this._config.artifacts;
89
95
  if (!rootDir || !plugins) {
90
96
  return false;
@@ -107,7 +113,7 @@ class DetoxLogFinalizer {
107
113
  const result = {};
108
114
  streamUtils().uniteSessionLogs(logs)
109
115
  .on('end', () => resolve(result))
110
- .on('error', (err) => reject(err))
116
+ .on('error', /* istanbul ignore next */ (err) => reject(err))
111
117
  .on('data', (event) => {
112
118
  const { ph, pid, tid, cat } = event;
113
119
  if (ph === 'B' || ph === 'i') {
@@ -6,6 +6,8 @@ const RESERVED_PROPERTIES = [
6
6
  'msg',
7
7
  'name',
8
8
  'pid',
9
+ 'tid',
10
+ 'ph',
9
11
  'time',
10
12
  ];
11
13
 
@@ -22,7 +24,7 @@ function escapeCallback(value, key) {
22
24
  }
23
25
 
24
26
  function sanitizeBunyanContext(context) {
25
- return hasReservedProperties(context) ? _.mapKeys(context, escapeCallback) : context;
27
+ return context && hasReservedProperties(context) ? _.mapKeys(context, escapeCallback) : context;
26
28
  }
27
29
 
28
30
  module.exports = sanitizeBunyanContext;
@@ -1,45 +1,34 @@
1
1
  const methods = {
2
2
  startSection(logger) {
3
- return (msg, args) => logger.trace.begin(args, msg);
3
+ return (msg, args) => {
4
+ if (args !== undefined) {
5
+ return logger.trace.begin(args, msg);
6
+ } else {
7
+ return logger.trace.begin(msg);
8
+ }
9
+ };
4
10
  },
5
11
 
6
12
  endSection(logger) {
7
- return (msg, args) => logger.trace.end(args);
13
+ return (_msg, args) => {
14
+ if (args !== undefined) {
15
+ return logger.trace.end(args);
16
+ } else {
17
+ return logger.trace.end();
18
+ }
19
+ };
8
20
  },
9
21
 
10
22
  traceCall(logger) {
11
23
  return (name, action, args = {}) => logger.trace.complete(args, name, action);
12
24
  },
13
-
14
- invocationCall(logger) {
15
- return (sectionName, invocation, action) => {
16
- return logger.trace.complete({
17
- cat: 'ws-client,ws-client-invocation',
18
- data: invocation,
19
- stack: _getCallStackTrace(),
20
- }, sectionName, action);
21
- };
22
- },
23
25
  };
24
26
 
25
- function _getCallStackTrace() {
26
- return new Error().stack
27
- .split('\n')
28
- .slice(1) // Ignore Error message
29
- .map(line => line
30
- .replace(/^\s*at\s+/, '')
31
- .replace(process.cwd(), '')
32
- )
33
- .filter(line => !line.includes('/detox/src')) // Ignore detox internal calls
34
- .join('\n');
35
- }
36
-
37
27
  function installLegacyTracerInterface(logger, target) {
38
28
  target.traceCall = methods.traceCall(logger);
39
29
  target.trace = Object.freeze({
40
30
  startSection: methods.startSection(logger),
41
31
  endSection: methods.endSection(logger),
42
- invocationCall: methods.invocationCall(logger),
43
32
  });
44
33
 
45
34
  return this;
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * @type {Detox.Logger}
3
3
  */
4
- module.exports = require('../..').log;
4
+ module.exports = require('../../internals').log;
@@ -0,0 +1,21 @@
1
+ function _getCallStackTrace() {
2
+ return new Error().stack
3
+ .split('\n')
4
+ .slice(1) // Ignore Error message
5
+ .map(line => line
6
+ .replace(/^\s*at\s+/, '')
7
+ .replace(process.cwd(), '')
8
+ )
9
+ .filter(line => !line.includes('/detox/src')) // Ignore detox internal calls
10
+ .join('\n');
11
+ }
12
+
13
+ function invocationCall(logger, sectionName, invocation, action) {
14
+ return logger.trace.complete({
15
+ cat: 'ws-client,ws-client-invocation',
16
+ data: invocation,
17
+ stack: _getCallStackTrace(),
18
+ }, sectionName, action);
19
+ }
20
+
21
+ module.exports = invocationCall;
@@ -1 +0,0 @@
1
- 31332781d3002ae93a1eaec77474e9f55bc7e5c7
@@ -1 +0,0 @@
1
- dcdfc5160bc82d542532fabc0b278164e550b9df0fc3f7a5afe6beaff60701f5
@@ -1 +0,0 @@
1
- 71f4200bf6199efed9fb74fb1cd92570ed90abbe4bdf7c37816571c49af0d0559fcb943eafac23fd3a4e4004b822bb2248e062185df77ea13110acc9b0a4c26d
@@ -1 +0,0 @@
1
- 04ee086f0aed13fd42de03340cc5c1d8d8749f6d
@@ -1 +0,0 @@
1
- 904c995d85c623ebe69096dba272c0e855d99b96c9997dfb2f4a2321b603356e
@@ -1 +0,0 @@
1
- fc2b80324b5b497e17a4e9adf5d7b06d003fca036559e7e61b39b8777e9238377e182f0959e54ee452053538fa1b17d65537158ed952b8b99e995d2fde590b0f
@@ -1 +0,0 @@
1
- c58bcf2c4a81d085044d69b52af78a5a
@@ -1 +0,0 @@
1
- d04a40498c30936d34cb2e8a41fea10936344a2f
@@ -1 +0,0 @@
1
- 4bd349ffd3768c46cd1bc7ce021607e38c08e8e7187a21d27b08aaf53dd52873
@@ -1 +0,0 @@
1
- c5c0556c23c72736ecd14d2227fdb65ddd100c1f47f460a6d1c02ae0a23a1a2774deb598ac56e2b7e6624aa028a3db00c312666233ea730b6bc7ed4863b6ebbf
@@ -1 +0,0 @@
1
- 8bd920eb4542d031002c33d93308f426
@@ -1 +0,0 @@
1
- 914ef3c1658d24794b7b94393578d899b16c0ed0
@@ -1 +0,0 @@
1
- a9b0b7bda22739644dee243f227c20d956ea3294378f75dea8d0f3d0d861d559
@@ -1 +0,0 @@
1
- 523b294c136c5be73335a2c75f3ebb8bce7aa79579810a7cd96cb28a69e000043dbf188b44e30b06ee5762fead96255c3efd272ab4d9a8691428510e055160d5
@@ -1,3 +0,0 @@
1
- const { trace, traceCall } = require('../..');
2
-
3
- module.exports = { trace, traceCall };