detox 20.0.2-breaking.new-global-lifecycle.0 → 20.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. package/Detox-android/com/wix/detox/{20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-javadoc.jar → 20.0.2/detox-20.0.2-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-sources.jar → 20.0.2/detox-20.0.2-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.pom → 20.0.2/detox-20.0.2.pom} +1 -7
  17. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.2/detox-20.0.2.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/README.md +1 -1
  29. package/android/build.gradle +12 -7
  30. package/android/detox/build.gradle +13 -9
  31. package/android/detox/proguard-rules-app.pro +6 -0
  32. package/android/detox/proguard-rules.pro +3 -0
  33. package/android/detox/publishing.gradle +27 -27
  34. package/android/detox/src/full/java/com/wix/detox/DetoxCrashHandler.kt +1 -1
  35. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  36. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +1 -1
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +15 -2
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +43 -38
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/IdlingResourceDescription.kt +19 -13
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +33 -30
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +7 -27
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +1 -11
  43. package/android/detox/src/main/java/com/wix/detox/common/TextFileReader.kt +1 -1
  44. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/DetoxMultiTapSpec.kt +4 -3
  45. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +61 -0
  46. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +3 -11
  47. package/index.d.ts +195 -59
  48. package/internals.d.ts +216 -49
  49. package/local-cli/build.js +2 -2
  50. package/local-cli/build.test.js +14 -14
  51. package/local-cli/cli.js +11 -6
  52. package/local-cli/init.js +61 -21
  53. package/local-cli/rebuild-framework-cache.js +1 -1
  54. package/local-cli/reset-lock-file.js +16 -0
  55. package/local-cli/templates/jest.js +13 -10
  56. package/local-cli/test.js +14 -8
  57. package/local-cli/test.test.js +143 -62
  58. package/local-cli/testCommand/TestRunnerCommand.js +97 -77
  59. package/local-cli/testCommand/TestRunnerError.js +17 -0
  60. package/local-cli/testCommand/TestRunnerError.test.js +25 -0
  61. package/local-cli/testCommand/builder.js +0 -1
  62. package/local-cli/testCommand/middlewares.js +4 -13
  63. package/local-cli/testCommand/warnings.js +0 -3
  64. package/local-cli/utils/jestInternals.js +4 -1
  65. package/package.json +23 -17
  66. package/runners/deprecation.js +42 -44
  67. package/runners/jest/globalSetup.js +1 -1
  68. package/runners/jest/globalTeardown.js +1 -1
  69. package/runners/jest/index.d.ts +60 -0
  70. package/runners/jest/index.js +3 -8
  71. package/runners/jest/index.test.js +13 -0
  72. package/runners/jest/reporters/DetoxReporter.js +33 -2
  73. package/runners/jest/testEnvironment/index.js +119 -69
  74. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +94 -47
  75. package/runners/jest/testEnvironment/listeners/DetoxPlatformFilterListener.js +1 -1
  76. package/runners/jest/testEnvironment/listeners/SpecReporter.js +14 -16
  77. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +2 -6
  78. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  79. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -1
  80. package/src/DetoxWorker.js +105 -62
  81. package/src/android/core/NativeElement.js +56 -20
  82. package/src/android/core/NativeExpect.js +28 -9
  83. package/src/android/interactions/native.js +25 -18
  84. package/src/artifacts/ArtifactsManager.js +14 -47
  85. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  86. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  87. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  88. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  89. package/src/artifacts/templates/plugin/ArtifactPlugin.js +1 -1
  90. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  91. package/src/artifacts/utils/temporaryPath.js +49 -8
  92. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  93. package/src/client/AsyncWebSocket.js +8 -17
  94. package/src/client/Client.js +19 -2
  95. package/src/client/actions/formatters/sync-resources/NetworkFormatter.js +1 -1
  96. package/src/configuration/collectCliConfig.js +1 -12
  97. package/src/configuration/composeAppsConfig.js +4 -0
  98. package/src/configuration/composeDeviceConfig.js +1 -1
  99. package/src/configuration/composeLoggerConfig.js +19 -10
  100. package/src/configuration/composeRunnerConfig.js +61 -9
  101. package/src/configuration/index.js +14 -9
  102. package/src/configuration/loadExternalConfig.js +1 -1
  103. package/src/devices/allocation/DeviceAllocator.js +3 -2
  104. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +5 -5
  105. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +4 -3
  106. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  107. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -2
  108. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  109. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +1 -1
  110. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  111. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  112. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  113. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  114. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  115. package/src/devices/common/drivers/android/tools/MonitoredInstrumentation.js +1 -1
  116. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +29 -3
  117. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +13 -15
  118. package/src/devices/runtime/RuntimeDevice.js +19 -12
  119. package/src/devices/runtime/drivers/DeviceDriverBase.js +1 -1
  120. package/src/devices/runtime/drivers/android/AndroidDriver.js +10 -2
  121. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +1 -1
  122. package/src/errors/DetoxConfigErrorComposer.js +17 -2
  123. package/src/errors/DetoxError.js +5 -1
  124. package/src/ios/expectTwo.js +153 -67
  125. package/src/ipc/IPCClient.js +12 -13
  126. package/src/ipc/IPCServer.js +28 -24
  127. package/src/ipc/{state.js → SessionState.js} +26 -53
  128. package/src/logger/DetoxLogger.js +287 -154
  129. package/src/logger/index.js +5 -0
  130. package/src/logger/utils/BunyanLogger.js +115 -0
  131. package/src/logger/utils/CategoryThreadDispatcher.js +37 -0
  132. package/src/logger/utils/DetoxLogFinalizer.js +162 -0
  133. package/src/logger/utils/MessageStack.js +35 -0
  134. package/src/logger/utils/ThreadDispatcher.js +61 -0
  135. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +23 -6
  136. package/src/logger/utils/getMainCategory.js +5 -0
  137. package/src/logger/utils/sanitizeBunyanContext.js +30 -0
  138. package/src/logger/utils/streams/BunyanTransformer.js +72 -0
  139. package/src/logger/utils/streams/ChromeTraceTransformer.js +127 -0
  140. package/src/logger/utils/streams/DetoxJSONLParser.js +31 -0
  141. package/src/logger/utils/streams/JSONLStringer.js +55 -0
  142. package/src/logger/utils/streams/index.js +7 -0
  143. package/src/logger/utils/streams/transformers.js +39 -0
  144. package/src/logger/utils/tracerLegacy.js +37 -0
  145. package/src/realms/DetoxContext.js +79 -65
  146. package/src/realms/DetoxInternalsFacade.js +8 -12
  147. package/src/realms/DetoxPrimaryContext.js +111 -72
  148. package/src/realms/DetoxSecondaryContext.js +29 -32
  149. package/src/server/DetoxConnection.js +18 -23
  150. package/src/server/DetoxServer.js +7 -10
  151. package/src/server/DetoxSession.js +6 -6
  152. package/src/server/DetoxSessionManager.js +1 -1
  153. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  154. package/src/symbols.js +16 -22
  155. package/src/utils/Timer.js +55 -38
  156. package/src/utils/argparse.js +11 -0
  157. package/src/utils/childProcess/exec.js +1 -1
  158. package/src/utils/childProcess/spawn.js +1 -1
  159. package/src/utils/errorUtils.js +24 -3
  160. package/src/utils/invocationTraceDescriptions.js +43 -0
  161. package/src/utils/logger.js +1 -1
  162. package/src/utils/pathUtils.js +11 -0
  163. package/src/utils/shellUtils.js +17 -0
  164. package/src/utils/traceInvocationCall.js +21 -0
  165. package/src/utils/traceMethods.js +15 -0
  166. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  167. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  168. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  169. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  170. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  171. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  172. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  173. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  174. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.aar +0 -0
  175. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.aar.md5 +0 -1
  176. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.aar.sha1 +0 -1
  177. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.aar.sha256 +0 -1
  178. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.aar.sha512 +0 -1
  179. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  180. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  181. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  182. package/Detox-android/com/wix/detox/20.0.2-breaking.new-global-lifecycle.0/detox-20.0.2-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  183. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategy.kt +0 -84
  184. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +0 -115
  185. package/runners/jest/deprecation.js +0 -25
  186. package/src/configuration/utils/warnings.js +0 -12
  187. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  188. package/src/logger/DetoxTracer.js +0 -133
  189. package/src/logger/TraceThreadDispatcher.js +0 -52
  190. package/src/utils/ChromeTracingExporter.js +0 -54
  191. package/src/utils/streamUtils.js +0 -214
  192. package/src/utils/trace.js +0 -19
@@ -1,4 +1,5 @@
1
1
  // @ts-nocheck
2
+ const assert = require('assert');
2
3
  const path = require('path');
3
4
 
4
5
  const fs = require('fs-extra');
@@ -6,6 +7,9 @@ const _ = require('lodash');
6
7
  const tempfile = require('tempfile');
7
8
 
8
9
  const { assertEnum, assertNormalized } = require('../utils/assertArgument');
10
+ const { actionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
11
+ const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
12
+ const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);
9
13
 
10
14
  const assertDirection = assertEnum(['left', 'right', 'up', 'down']);
11
15
  const assertSpeed = assertEnum(['fast', 'slow']);
@@ -23,7 +27,8 @@ class Expect {
23
27
  + (percent + (' (' + (typeof percent + ')'))));
24
28
  }
25
29
 
26
- return this.expect('toBeVisible', percent);
30
+ const traceDescription = expectDescription.toBeVisible(percent);
31
+ return this.expect('toBeVisible', traceDescription, percent);
27
32
  }
28
33
 
29
34
  toBeNotVisible() {
@@ -31,7 +36,8 @@ class Expect {
31
36
  }
32
37
 
33
38
  toBeFocused() {
34
- return this.expect('toBeFocused');
39
+ const traceDescription = expectDescription.toBeFocused();
40
+ return this.expect('toBeFocused', traceDescription);
35
41
  }
36
42
 
37
43
  toBeNotFocused() {
@@ -39,7 +45,8 @@ class Expect {
39
45
  }
40
46
 
41
47
  toExist() {
42
- return this.expect('toExist');
48
+ const traceDescription = expectDescription.toExist();
49
+ return this.expect('toExist', traceDescription);
43
50
  }
44
51
 
45
52
  toNotExist() {
@@ -47,7 +54,8 @@ class Expect {
47
54
  }
48
55
 
49
56
  toHaveText(text) {
50
- return this.expect('toHaveText', text);
57
+ const traceDescription = expectDescription.toHaveText(text);
58
+ return this.expect('toHaveText', traceDescription, text);
51
59
  }
52
60
 
53
61
  toNotHaveText(text) {
@@ -55,7 +63,8 @@ class Expect {
55
63
  }
56
64
 
57
65
  toHaveLabel(label) {
58
- return this.expect('toHaveLabel', label);
66
+ const traceDescription = expectDescription.toHaveLabel(label);
67
+ return this.expect('toHaveLabel', traceDescription, label);
59
68
  }
60
69
 
61
70
  toNotHaveLabel(label) {
@@ -63,7 +72,8 @@ class Expect {
63
72
  }
64
73
 
65
74
  toHaveId(id) {
66
- return this.expect('toHaveId', id);
75
+ const traceDescription = expectDescription.toHaveId(id);
76
+ return this.expect('toHaveId', traceDescription, id);
67
77
  }
68
78
 
69
79
  toNotHaveId(id) {
@@ -71,7 +81,8 @@ class Expect {
71
81
  }
72
82
 
73
83
  toHaveValue(value) {
74
- return this.expect('toHaveValue', value);
84
+ const traceDescription = expectDescription.toHaveValue(value);
85
+ return this.expect('toHaveValue', traceDescription, value);
75
86
  }
76
87
 
77
88
  toNotHaveValue(value) {
@@ -79,7 +90,8 @@ class Expect {
79
90
  }
80
91
 
81
92
  toHaveSliderPosition(position, tolerance = 0) {
82
- return this.expect('toHaveSliderPosition', position, tolerance);
93
+ const traceDescription = expectDescription.toHaveSliderPosition(position, tolerance);
94
+ return this.expect('toHaveSliderPosition', traceDescription, position, tolerance);
83
95
  }
84
96
 
85
97
  toHaveToggleValue(value) {
@@ -103,16 +115,18 @@ class Expect {
103
115
  };
104
116
  }
105
117
 
106
- expect(expectation, ...params) {
118
+ expect(expectation, traceDescription, ...params) {
119
+ assert(traceDescription, `must provide trace description for expectation: \n ${JSON.stringify(expectation)}`);
120
+
107
121
  const invocation = this.createInvocation(expectation, ...params);
108
- return this._invocationManager.execute(invocation);
122
+ traceDescription = expectDescription.full(traceDescription, this.modifiers.includes('not'));
123
+ return _executeInvocation(this._invocationManager, invocation, traceDescription);
109
124
  }
110
125
  }
111
126
 
112
127
  class InternalExpect extends Expect {
113
- expect(expectation, ...params) {
114
- const invocation = this.createInvocation(expectation, ...params);
115
- return invocation;
128
+ expect(expectation, _traceDescription, ...params) {
129
+ return this.createInvocation(expectation, ...params);
116
130
  }
117
131
  }
118
132
 
@@ -131,7 +145,8 @@ class Element {
131
145
  }
132
146
 
133
147
  getAttributes() {
134
- return this.withAction('getAttributes');
148
+ const traceDescription = actionDescription.getAttributes();
149
+ return this.withAction('getAttributes', traceDescription);
135
150
  }
136
151
 
137
152
  tap(point) {
@@ -140,12 +155,16 @@ class Element {
140
155
  if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')'))));
141
156
  if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')'))));
142
157
  }
143
- return this.withAction('tap', point);
158
+
159
+ const traceDescription = actionDescription.tapAtPoint(point);
160
+ return this.withAction('tap', traceDescription, point);
144
161
  }
145
162
 
146
163
  longPress(duration = 1000) {
147
164
  if (typeof duration !== 'number') throw new Error('duration should be a number, but got ' + (duration + (' (' + (typeof duration + ')'))));
148
- return this.withAction('longPress', duration);
165
+
166
+ const traceDescription = actionDescription.longPress(duration);
167
+ return this.withAction('longPress', traceDescription, duration);
149
168
  }
150
169
 
151
170
  longPressAndDrag(duration, normalizedPositionX, normalizedPositionY, targetElement,
@@ -162,13 +181,18 @@ class Element {
162
181
  assertNormalized({ normalizedTargetPositionX });
163
182
  assertNormalized({ normalizedTargetPositionY });
164
183
 
165
- return this.withActionAndTargetElement('longPress', targetElement, duration, normalizedPositionX, normalizedPositionY,
184
+ const traceDescription = actionDescription.longPressAndDrag(duration, normalizedPositionX, normalizedPositionY, targetElement,
185
+ normalizedTargetPositionX, normalizedTargetPositionY, speed, holdDuration);
186
+ return this.withActionAndTargetElement('longPress', targetElement, traceDescription, duration, normalizedPositionX, normalizedPositionY,
166
187
  normalizedTargetPositionX, normalizedTargetPositionY, speed, holdDuration);
167
188
  }
168
189
 
169
190
  multiTap(times) {
170
191
  if (typeof times !== 'number') throw new Error('times should be a number, but got ' + (times + (' (' + (typeof times + ')'))));
171
- return this.withAction('multiTap', times);
192
+ if (times < 1) throw new Error('times should be greater than 0, but got ' + times);
193
+
194
+ const traceDescription = actionDescription.multiTap(times);
195
+ return this.withAction('multiTap', traceDescription, times);
172
196
  }
173
197
 
174
198
  tapAtPoint(point) {
@@ -176,25 +200,32 @@ class Element {
176
200
  }
177
201
 
178
202
  tapBackspaceKey() {
179
- return this.withAction('tapBackspaceKey');
203
+ const traceDescription = actionDescription.tapBackspaceKey();
204
+ return this.withAction('tapBackspaceKey', traceDescription);
180
205
  }
181
206
 
182
207
  tapReturnKey() {
183
- return this.withAction('tapReturnKey');
208
+ const traceDescription = actionDescription.tapReturnKey();
209
+ return this.withAction('tapReturnKey', traceDescription);
184
210
  }
185
211
 
186
212
  typeText(text) {
187
213
  if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')'))));
188
- return this.withAction('typeText', text);
214
+
215
+ const traceDescription = actionDescription.typeText(text);
216
+ return this.withAction('typeText', traceDescription, text);
189
217
  }
190
218
 
191
219
  replaceText(text) {
192
220
  if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')'))));
193
- return this.withAction('replaceText', text);
221
+
222
+ const traceDescription = actionDescription.replaceText(text);
223
+ return this.withAction('replaceText', traceDescription, text);
194
224
  }
195
225
 
196
226
  clearText() {
197
- return this.withAction('clearText');
227
+ const traceDescription = actionDescription.clearText();
228
+ return this.withAction('clearText', traceDescription);
198
229
  }
199
230
 
200
231
  scroll(pixels, direction = 'down', startPositionX = NaN, startPositionY = NaN) {
@@ -202,12 +233,15 @@ class Element {
202
233
  if (typeof pixels !== 'number') throw new Error('amount of pixels should be a number, but got ' + (pixels + (' (' + (typeof pixels + ')'))));
203
234
  if (typeof startPositionX !== 'number') throw new Error('startPositionX should be a number, but got ' + (startPositionX + (' (' + (typeof startPositionX + ')'))));
204
235
  if (typeof startPositionY !== 'number') throw new Error('startPositionY should be a number, but got ' + (startPositionY + (' (' + (typeof startPositionY + ')'))));
205
- return this.withAction('scroll', pixels, direction, startPositionX, startPositionY);
236
+
237
+ const traceDescription = actionDescription.scroll(pixels, direction, startPositionX, startPositionY);
238
+ return this.withAction('scroll', traceDescription, pixels, direction, startPositionX, startPositionY);
206
239
  }
207
240
 
208
241
  scrollTo(edge) {
209
242
  if (!['left', 'right', 'top', 'bottom'].some(option => option === edge)) throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge);
210
- return this.withAction('scrollTo', edge);
243
+ const traceDescription = actionDescription.scrollTo(edge);
244
+ return this.withAction('scrollTo', traceDescription, edge);
211
245
  }
212
246
 
213
247
  swipe(direction, speed = 'fast', normalizedSwipeOffset = NaN, normalizedStartingPointX = NaN, normalizedStartingPointY = NaN) {
@@ -218,42 +252,62 @@ class Element {
218
252
  assertNormalized({ normalizedStartingPointY });
219
253
 
220
254
  normalizedSwipeOffset = Number.isNaN(normalizedSwipeOffset) ? 0.75 : normalizedSwipeOffset;
221
- return this.withAction('swipe', direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
255
+ const traceDescription = actionDescription.swipe(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
256
+ return this.withAction(
257
+ 'swipe',
258
+ traceDescription,
259
+ direction,
260
+ speed,
261
+ normalizedSwipeOffset,
262
+ normalizedStartingPointX,
263
+ normalizedStartingPointY
264
+ );
222
265
  }
223
266
 
224
267
  setColumnToValue(column, value) {
225
268
  if (typeof column !== 'number') throw new Error('column should be a number, but got ' + (column + (' (' + (typeof column + ')'))));
226
269
  if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')'))));
227
- return this.withAction('setColumnToValue', column, value);
270
+
271
+ const traceDescription = actionDescription.setColumnToValue(column, value);
272
+ return this.withAction('setColumnToValue', traceDescription, column, value);
228
273
  }
229
274
 
230
275
  setDatePickerDate(dateString, dateFormat) {
231
276
  if (typeof dateString !== 'string') throw new Error('dateString should be a string, but got ' + (dateString + (' (' + (typeof dateString + ')'))));
232
277
  if (typeof dateFormat !== 'string') throw new Error('dateFormat should be a string, but got ' + (dateFormat + (' (' + (typeof dateFormat + ')'))));
233
- return this.withAction('setDatePickerDate', dateString, dateFormat);
278
+
279
+ const traceDescription = actionDescription.setDatePickerDate(dateString, dateFormat);
280
+ return this.withAction('setDatePickerDate', traceDescription, dateString, dateFormat);
234
281
  }
235
282
 
236
283
  pinch(scale, speed = 'fast', angle = 0) {
237
284
  if (typeof scale !== 'number' || !Number.isFinite(scale) || scale < 0) throw new Error(`pinch scale must be a finite number larger than zero`);
238
285
  if (!['slow', 'fast'].includes(speed)) throw new Error(`pinch speed is either 'slow' or 'fast'`);
239
286
  if (typeof angle !== 'number' || !Number.isFinite(angle)) throw new Error(`pinch angle must be a finite number (radian)`);
240
- return this.withAction('pinch', scale, speed, angle);
287
+
288
+ const traceDescription = actionDescription.pinch(scale, speed, angle);
289
+ return this.withAction('pinch', traceDescription, scale, speed, angle);
241
290
  }
242
291
 
243
292
  pinchWithAngle(direction, speed = 'slow', angle = 0) {
244
293
  if (!['inward', 'outward'].includes(direction)) throw new Error(`pinchWithAngle direction is either 'inward' or 'outward'`);
245
294
  if (!['slow', 'fast'].includes(speed)) throw new Error(`pinchWithAngle speed is either 'slow' or 'fast'`);
246
295
  if (typeof angle !== 'number') throw new Error(`pinchWithAngle angle must be a number (radiant), got ${typeof angle}`);
247
- return this.withAction('pinchWithAngle', direction, speed, angle);
296
+
297
+ const traceDescription = actionDescription.pinchWithAngle(direction, speed, angle);
298
+ return this.withAction('pinchWithAngle', traceDescription, direction, speed, angle);
248
299
  }
249
300
 
250
301
  adjustSliderToPosition(position) {
251
302
  if (!(typeof position === 'number' && position >= 0 && position <= 1)) throw new Error('position should be a number [0.0, 1.0], but got ' + (position + (' (' + (typeof position + ')'))));
252
- return this.withAction('adjustSliderToPosition', position);
303
+
304
+ const traceDescription = actionDescription.adjustSliderToPosition(position);
305
+ return this.withAction('adjustSliderToPosition', traceDescription, position);
253
306
  }
254
307
 
255
308
  async takeScreenshot(fileName) {
256
- const { screenshotPath } = await this.withAction('takeScreenshot', fileName);
309
+ const traceDescription = actionDescription.takeScreenshot(fileName);
310
+ const { screenshotPath } = await this.withAction('takeScreenshot', traceDescription, fileName);
257
311
 
258
312
  const filePath = tempfile('.detox.element-screenshot.png');
259
313
  await fs.move(screenshotPath, filePath);
@@ -287,22 +341,20 @@ class Element {
287
341
  return invocation;
288
342
  }
289
343
 
290
- withAction(action, ...params) {
344
+ withAction(action, traceDescription, ...params) {
291
345
  const invocation = this.createInvocation(action, null, ...params);
292
- return this._invocationManager.execute(invocation);
346
+ return _executeInvocation(this._invocationManager, invocation, traceDescription);
293
347
  }
294
348
 
295
- withActionAndTargetElement(action, targetElement, ...params) {
349
+ withActionAndTargetElement(action, targetElement, traceDescription, ...params) {
296
350
  const invocation = this.createInvocation(action, targetElement, ...params);
297
- return this._invocationManager.execute(invocation);
351
+ return _executeInvocation(this._invocationManager, invocation, traceDescription);
298
352
  }
299
353
  }
300
354
 
301
355
  class InternalElement extends Element {
302
-
303
- withAction(action, ...params) {
304
- const invocation = this.createInvocation(action, null, ...params);
305
- return invocation;
356
+ withAction(action, _traceDescription, ...params) {
357
+ return this.createInvocation(action, null, ...params);
306
358
  }
307
359
  }
308
360
 
@@ -341,7 +393,6 @@ class By {
341
393
  }
342
394
 
343
395
  class Matcher {
344
-
345
396
  accessibilityLabel(label) {
346
397
  return this.label(label);
347
398
  }
@@ -395,14 +446,12 @@ class Matcher {
395
446
  if (!(matcher instanceof Matcher)) {
396
447
  throwMatcherError(matcher);
397
448
  }
449
+
398
450
  this.and({ predicate: { type: 'descendant', predicate: matcher.predicate } });
399
451
  return this;
400
452
  }
401
453
 
402
454
  and(matcher) {
403
- // if (!(matcher instanceof Matcher)) {
404
- // throwMatcherError(matcher);
405
- // }
406
455
  const tempPredicate = this.predicate;
407
456
  delete this.predicate;
408
457
  this.predicate = { type: 'and', predicates: [] };
@@ -493,7 +542,9 @@ class WaitFor {
493
542
  if (typeof timeout !== 'number') throw new Error('text should be a number, but got ' + (timeout + (' (' + (typeof timeout + ')'))));
494
543
  if (timeout < 0) throw new Error('timeout must be larger than 0');
495
544
  this.timeout = timeout;
496
- return this.waitForWithTimeout();
545
+
546
+ const traceDescription = expectDescription.withTimeout(timeout);
547
+ return this.waitForWithTimeout(traceDescription);
497
548
  }
498
549
 
499
550
  whileElement(matcher) {
@@ -504,106 +555,137 @@ class WaitFor {
504
555
 
505
556
  tap(point) {
506
557
  this.action = this.actionableElement.tap(point);
507
- return this.waitForWithAction();
558
+ const traceDescription = actionDescription.tapAtPoint(point);
559
+ return this.waitForWithAction(traceDescription);
508
560
  }
509
561
 
510
562
  longPress(duration) {
511
563
  this.action = this.actionableElement.longPress(duration);
512
- return this.waitForWithAction();
564
+ const traceDescription = actionDescription.longPress(duration);
565
+ return this.waitForWithAction(traceDescription);
513
566
  }
514
567
 
515
568
  multiTap(times) {
516
569
  this.action = this.actionableElement.multiTap(times);
517
- return this.waitForWithAction();
570
+ const traceDescription = actionDescription.multiTap(times);
571
+ return this.waitForWithAction(traceDescription);
518
572
  }
519
573
 
520
574
  tapAtPoint(point) {
521
575
  this.action = this.actionableElement.tap(point);
522
- return this.waitForWithAction();
576
+ const traceDescription = actionDescription.tapAtPoint(point);
577
+ return this.waitForWithAction(traceDescription);
523
578
  }
524
579
 
525
580
  tapBackspaceKey() {
526
581
  this.action = this.actionableElement.tapBackspaceKey();
527
- return this.waitForWithAction();
582
+ const traceDescription = actionDescription.tapBackspaceKey();
583
+ return this.waitForWithAction(traceDescription);
528
584
  }
529
585
 
530
586
  tapReturnKey() {
531
587
  this.action = this.actionableElement.tapReturnKey();
532
- return this.waitForWithAction();
588
+ const traceDescription = actionDescription.tapReturnKey();
589
+ return this.waitForWithAction(traceDescription);
533
590
  }
534
591
 
535
592
  typeText(text) {
536
593
  this.action = this.actionableElement.typeText(text);
537
- return this.waitForWithAction();
594
+ const traceDescription = actionDescription.typeText(text);
595
+ return this.waitForWithAction(traceDescription);
538
596
  }
539
597
 
540
598
  replaceText(text) {
541
599
  this.action = this.actionableElement.replaceText(text);
542
- return this.waitForWithAction();
600
+ const traceDescription = actionDescription.replaceText(text);
601
+ return this.waitForWithAction(traceDescription);
543
602
  }
544
603
 
545
604
  clearText() {
546
605
  this.action = this.actionableElement.clearText();
547
- return this.waitForWithAction();
606
+ const traceDescription = actionDescription.clearText();
607
+ return this.waitForWithAction(traceDescription);
548
608
  }
549
609
 
550
610
  scroll(pixels, direction, startPositionX, startPositionY) {
551
611
  this.action = this.actionableElement.scroll(pixels, direction, startPositionX, startPositionY);
552
- return this.waitForWithAction();
612
+
613
+ const traceDescription = actionDescription.scroll(pixels, direction, startPositionX, startPositionY);
614
+ return this.waitForWithAction(traceDescription);
553
615
  }
554
616
 
555
617
  scrollTo(edge) {
556
618
  this.action = this.actionableElement.scrollTo(edge);
557
- return this.waitForWithAction();
619
+ const traceDescription = actionDescription.scrollTo(edge);
620
+ return this.waitForWithAction(traceDescription);
558
621
  }
559
622
 
560
623
  swipe(direction, speed, percentage) {
561
624
  this.action = this.actionableElement.swipe(direction, speed, percentage);
562
- return this.waitForWithAction();
625
+ const traceDescription = actionDescription.swipe(direction, speed, percentage);
626
+ return this.waitForWithAction(traceDescription);
563
627
  }
564
628
 
565
629
  setColumnToValue(column, value) {
566
630
  this.action = this.actionableElement.setColumnToValue(column, value);
567
- return this.waitForWithAction();
631
+ const traceDescription = actionDescription.setColumnToValue(column, value);
632
+ return this.waitForWithAction(traceDescription);
568
633
  }
569
634
 
570
635
  setDatePickerDate(dateString, dateFormat) {
571
636
  this.action = this.actionableElement.setDatePickerDate(dateString, dateFormat);
572
- return this.waitForWithAction();
637
+ const traceDescription = actionDescription.setDatePickerDate(dateString, dateFormat);
638
+ return this.waitForWithAction(traceDescription);
573
639
  }
574
640
 
575
641
  pinch(scale, speed, angle) {
576
642
  this.action = this.actionableElement.pinch(scale, speed, angle);
577
- return this.waitForWithAction();
643
+ const traceDescription = actionDescription.pinch(scale, speed, angle);
644
+ return this.waitForWithAction(traceDescription);
578
645
  }
579
646
 
580
647
  pinchWithAngle(direction, speed, angle) {
581
648
  this.action = this.actionableElement.pinchWithAngle(direction, speed, angle);
582
- return this.waitForWithAction();
649
+ const traceDescription = actionDescription.pinchWithAngle(direction, speed, angle);
650
+ return this.waitForWithAction(traceDescription);
583
651
  }
584
652
 
585
- waitForWithAction() {
653
+ waitForWithAction(actionTraceDescription) {
586
654
  const expectation = this.expectation;
587
655
  const action = this.action;
588
656
 
589
- return this._invocationManager.execute({
657
+ const invocation = this.createWaitForWithActionInvocation(expectation, action);
658
+
659
+ const traceDescription = expectDescription.waitFor(actionTraceDescription);
660
+ return _executeInvocation(this._invocationManager, invocation, traceDescription);
661
+ }
662
+
663
+ createWaitForWithActionInvocation(expectation, action) {
664
+ return {
590
665
  ...action,
591
666
  while: {
592
667
  ...expectation
593
668
  }
594
- });
669
+ };
595
670
  }
596
671
 
597
- waitForWithTimeout() {
672
+ waitForWithTimeout(expectTraceDescription) {
598
673
  const expectation = this.expectation;
599
674
  const action = this.action;
600
675
  const timeout = this.timeout;
601
676
 
602
- return this._invocationManager.execute({
677
+ const invocation = this.createWaitForWithTimeoutInvocation(expectation, action, timeout);
678
+
679
+ const traceDescription = expectDescription.waitForWithTimeout(expectTraceDescription, timeout);
680
+ return _executeInvocation(this._invocationManager, invocation, traceDescription);
681
+ }
682
+
683
+ createWaitForWithTimeoutInvocation(expectation, action, timeout) {
684
+ return {
603
685
  ...action,
604
686
  ...expectation,
605
687
  timeout
606
- });
688
+ };
607
689
  }
608
690
  }
609
691
 
@@ -665,4 +747,8 @@ function throwElementError(param) {
665
747
  throw new Error(`${param} is not a Detox element. More about Detox elements here: https://wix.github.io/Detox/docs/api/matchers`);
666
748
  }
667
749
 
750
+ function _executeInvocation(invocationManager, invocation, traceDescription) {
751
+ return traceInvocationCall(traceDescription, invocation, invocationManager.execute(invocation));
752
+ }
753
+
668
754
  module.exports = IosExpect;
@@ -1,13 +1,14 @@
1
1
  const { IPC } = require('node-ipc');
2
2
 
3
3
  const { DetoxInternalError } = require('../errors');
4
+ const { serializeObjectWithError } = require('../utils/errorUtils');
4
5
 
5
6
  class IPCClient {
6
7
  constructor({ id, logger, state }) {
7
8
  this._id = id;
8
9
  /** @type {import('../logger/DetoxLogger')} logger */
9
- this._logger = logger.child({ __filename, cat: 'ipc' });
10
- /** @type {import('./state').SecondarySessionState} */
10
+ this._logger = logger.child({ cat: 'ipc' });
11
+ /** @type {import('./SessionState')} */
11
12
  this._state = state;
12
13
 
13
14
  this._client = null;
@@ -47,16 +48,18 @@ class IPCClient {
47
48
  }
48
49
 
49
50
  async registerWorker(workerId) {
50
- this._state.workerId = workerId;
51
- await this._emit('registerWorker', { workerId });
51
+ const sessionState = await this._emit('registerWorker', { workerId });
52
+ this._state.patch(sessionState);
52
53
  }
53
54
 
54
55
  /**
55
- * @param {string[]} testFilePaths
56
- * @param {Boolean} permanent
56
+ * @param {DetoxInternals.DetoxTestFileReport[]} testResults
57
57
  */
58
- async reportFailedTests(testFilePaths, permanent) {
59
- await this._emit('failedTests', { testFilePaths, permanent });
58
+ async reportTestResults(testResults) {
59
+ const sessionState = await this._emit('reportTestResults', {
60
+ testResults: testResults.map(r => serializeObjectWithError(r, 'testExecError')),
61
+ });
62
+ this._state.patch(sessionState);
60
63
  }
61
64
 
62
65
  async _connectToServer() {
@@ -75,11 +78,7 @@ class IPCClient {
75
78
  }
76
79
 
77
80
  async _registerContext() {
78
- const sessionState = await this._emit('registerContext', {
79
- id: this._id,
80
- logFile: this._logger.file,
81
- });
82
-
81
+ const sessionState = await this._emit('registerContext', { id: this._id });
83
82
  this._state.patch(sessionState);
84
83
  }
85
84
 
@@ -1,15 +1,19 @@
1
+ const { uniqBy } = require('lodash');
1
2
  const { IPC } = require('node-ipc');
2
3
 
4
+ const { serializeObjectWithError } = require('../utils/errorUtils');
5
+
3
6
  class IPCServer {
4
7
  /**
5
8
  * @param {object} options
6
- * @param {import('./state').PrimarySessionState} options.sessionState
9
+ * @param {import('./SessionState')} options.sessionState
7
10
  * @param {Detox.Logger} options.logger
8
11
  */
9
12
  constructor({ sessionState, logger }) {
10
13
  this._sessionState = sessionState;
11
- this._logger = logger.child({ __filename, cat: 'ipc' });
14
+ this._logger = logger.child({ cat: 'ipc,ipc-server' });
12
15
  this._ipc = null;
16
+ this._workers = new Set();
13
17
  }
14
18
 
15
19
  get id() {
@@ -26,12 +30,12 @@ class IPCServer {
26
30
  this._ipc.config.appspace = 'detox.';
27
31
  this._ipc.config.logger = (msg) => this._logger.trace(msg);
28
32
 
29
- await new Promise((resolve) => {
33
+ await new Promise((resolve) => {
30
34
  // TODO: handle reject
31
35
  this._ipc.serve(() => resolve());
32
36
  this._ipc.server.on('registerContext', this.onRegisterContext.bind(this));
33
37
  this._ipc.server.on('registerWorker', this.onRegisterWorker.bind(this));
34
- this._ipc.server.on('failedTests', this.onFailedTests.bind(this));
38
+ this._ipc.server.on('reportTestResults', this.onReportTestResults.bind(this));
35
39
  this._ipc.server.start();
36
40
  });
37
41
  }
@@ -48,45 +52,45 @@ class IPCServer {
48
52
  });
49
53
  }
50
54
 
51
- onRegisterContext({ id, logFile }, socket) {
55
+ onRegisterContext({ id }, socket) {
52
56
  this._sessionState.contexts.push(id);
53
57
 
54
- if (logFile && !this._sessionState.logFiles.includes(logFile)) {
55
- this._sessionState.logFiles.push(logFile);
56
- }
57
-
58
58
  this._ipc.server.emit(socket, 'registerContextDone', {
59
- failedTestFiles: this._sessionState.failedTestFiles,
60
- testFilesToRetry: this._sessionState.testFilesToRetry,
59
+ testResults: this._sessionState.testResults,
61
60
  testSessionIndex: this._sessionState.testSessionIndex,
62
61
  });
63
62
  }
64
63
 
65
- onRegisterWorker({ workerId }, socket) {
64
+ onRegisterWorker({ workerId }, socket = null) {
65
+ const workersCount = this._workers.add(workerId).size;
66
+ const shouldBroadcast = workersCount > this._sessionState.workersCount;
67
+ this._sessionState.workersCount = workersCount;
68
+
66
69
  if (socket) {
67
- this._ipc.server.emit(socket, 'registerWorkerDone', {});
70
+ this._ipc.server.emit(socket, 'registerWorkerDone', { workersCount });
68
71
  }
69
72
 
70
- if (workerId > this._sessionState.workersCount) {
71
- const workersCount = this._sessionState.workersCount = workerId;
73
+ if (shouldBroadcast) {
72
74
  this._ipc.server.broadcast('sessionStateUpdate', { workersCount });
73
75
  }
74
76
  }
75
77
 
76
- onFailedTests({ testFilePaths, permanent }, socket = null) {
77
- if (permanent) {
78
- this._sessionState.failedTestFiles.push(...testFilePaths);
79
- } else {
80
- this._sessionState.testFilesToRetry.push(...testFilePaths);
81
- }
78
+ onReportTestResults({ testResults }, socket = null) {
79
+ const merged = uniqBy([
80
+ ...testResults.map(r => serializeObjectWithError(r, 'testExecError')),
81
+ ...this._sessionState.testResults
82
+ ], 'testFilePath');
83
+
84
+ this._sessionState.testResults.splice(0, Infinity, ...merged);
82
85
 
83
86
  if (socket) {
84
- this._ipc.server.emit(socket, 'failedTestsDone', {});
87
+ this._ipc.server.emit(socket, 'reportTestResultsDone', {
88
+ testResults: this._sessionState.testResults,
89
+ });
85
90
  }
86
91
 
87
92
  this._ipc.server.broadcast('sessionStateUpdate', {
88
- failedTestFiles: this._sessionState.failedTestFiles,
89
- testFilesToRetry: this._sessionState.testFilesToRetry,
93
+ testResults: this._sessionState.testResults,
90
94
  });
91
95
  }
92
96
  }