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
@@ -5,6 +5,7 @@ const tempfile = require('tempfile');
5
5
 
6
6
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
7
7
  const invoke = require('../../invoke');
8
+ const { actionDescription } = require('../../utils/invocationTraceDescriptions');
8
9
  const actions = require('../actions/native');
9
10
  const DetoxMatcherApi = require('../espressoapi/DetoxMatcher');
10
11
  const { ActionInteraction } = require('../interactions/native');
@@ -18,12 +19,11 @@ class NativeElement {
18
19
  }
19
20
 
20
21
  _selectElementWithMatcher(matcher) {
21
- // if (!(matcher instanceof NativeMatcher)) throw new DetoxRuntimeError(`Element _selectElementWithMatcher argument must be a valid NativeMatcher, got ${typeof matcher}`);
22
22
  this._call = invoke.call(invoke.Espresso, 'onView', matcher._call);
23
23
  }
24
24
 
25
25
  atIndex(index) {
26
- if (typeof index !== 'number') throw new DetoxRuntimeError(`Element atIndex argument must be a number, got ${typeof index}`);
26
+ if (typeof index !== 'number') throw new DetoxRuntimeError({ message: `Element atIndex argument must be a number, got ${typeof index}` });
27
27
  const matcher = this._originalMatcher;
28
28
  this._originalMatcher._call = invoke.callDirectly(DetoxMatcherApi.matcherForAtIndex(index, matcher._call.value));
29
29
 
@@ -32,56 +32,84 @@ class NativeElement {
32
32
  }
33
33
 
34
34
  async tap(value) {
35
- return await new ActionInteraction(this._invocationManager, this, new actions.TapAction(value)).execute();
35
+ const action = new actions.TapAction(value);
36
+ const traceDescription = actionDescription.tapAtPoint(value);
37
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
36
38
  }
37
39
 
38
40
  async tapAtPoint(value) {
39
- return await new ActionInteraction(this._invocationManager, this, new actions.TapAtPointAction(value)).execute();
41
+ const action = new actions.TapAtPointAction(value);
42
+ const traceDescription = actionDescription.tapAtPoint(value);
43
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
40
44
  }
41
45
 
42
46
  async longPress() {
43
- return await new ActionInteraction(this._invocationManager, this, new actions.LongPressAction()).execute();
47
+ const action = new actions.LongPressAction();
48
+ const traceDescription = actionDescription.longPress();
49
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
44
50
  }
45
51
 
46
52
  async multiTap(times) {
47
- return await new ActionInteraction(this._invocationManager, this, new actions.MultiClickAction(times)).execute();
53
+ if (typeof times !== 'number') throw new Error('times should be a number, but got ' + (times + (' (' + (typeof times + ')'))));
54
+ if (times < 1) throw new Error('times should be greater than 0, but got ' + times);
55
+
56
+ const action = new actions.MultiClickAction(times);
57
+ const traceDescription = actionDescription.multiTap(times);
58
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
48
59
  }
49
60
 
50
61
  async tapBackspaceKey() {
51
- return await new ActionInteraction(this._invocationManager, this, new actions.PressKeyAction(67)).execute();
62
+ const action = new actions.PressKeyAction(67);
63
+ const traceDescription = actionDescription.tapBackspaceKey();
64
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
52
65
  }
53
66
 
54
67
  async tapReturnKey() {
55
- return await new ActionInteraction(this._invocationManager, this, new actions.TypeTextAction('\n')).execute();
68
+ const action = new actions.TypeTextAction('\n');
69
+ const traceDescription = actionDescription.tapReturnKey();
70
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
56
71
  }
57
72
 
58
73
  async typeText(value) {
59
- return await new ActionInteraction(this._invocationManager, this, new actions.TypeTextAction(value)).execute();
74
+ const action = new actions.TypeTextAction(value);
75
+ const traceDescription = actionDescription.typeText(value);
76
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
60
77
  }
61
78
 
62
79
  async replaceText(value) {
63
- return await new ActionInteraction(this._invocationManager, this, new actions.ReplaceTextAction(value)).execute();
80
+ const action = new actions.ReplaceTextAction(value);
81
+ const traceDescription = actionDescription.replaceText(value);
82
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
64
83
  }
65
84
 
66
85
  async clearText() {
67
- return await new ActionInteraction(this._invocationManager, this, new actions.ClearTextAction()).execute();
86
+ const action = new actions.ClearTextAction();
87
+ const traceDescription = actionDescription.clearText();
88
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
68
89
  }
69
90
 
70
91
  async scroll(amount, direction = 'down', startPositionX, startPositionY) {
71
- // override the user's element selection with an extended matcher that looks for UIScrollView children
72
- // this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews());
73
- return await new ActionInteraction(this._invocationManager, this, new actions.ScrollAmountAction(direction, amount, startPositionX, startPositionY)).execute();
92
+ const action = new actions.ScrollAmountAction(direction, amount, startPositionX, startPositionY);
93
+ const traceDescription = actionDescription.scroll(amount, direction, startPositionX, startPositionY);
94
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
74
95
  }
75
96
 
76
97
  async scrollTo(edge) {
77
98
  // override the user's element selection with an extended matcher that looks for UIScrollView children
78
99
  this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews());
79
- return await new ActionInteraction(this._invocationManager, this, new actions.ScrollEdgeAction(edge)).execute();
100
+
101
+ const action = new actions.ScrollEdgeAction(edge);
102
+ const traceDescription = actionDescription.scrollTo(edge);
103
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
80
104
  }
81
105
 
82
106
  async scrollToIndex(index) {
107
+ // override the user's element selection with an extended matcher that looks for UIScrollView children
83
108
  this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews());
84
- return await new ActionInteraction(this._invocationManager, this, new actions.ScrollToIndex(index)).execute();
109
+
110
+ const action = new actions.ScrollToIndex(index);
111
+ const traceDescription = actionDescription.scrollToIndex(index);
112
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
85
113
  }
86
114
 
87
115
  /**
@@ -96,13 +124,17 @@ class NativeElement {
96
124
 
97
125
  // override the user's element selection with an extended matcher that avoids RN issues with RCTScrollView
98
126
  this._selectElementWithMatcher(this._originalMatcher._avoidProblematicReactNativeElements());
127
+
99
128
  const action = new actions.SwipeAction(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
100
- return await new ActionInteraction(this._invocationManager, this, action).execute();
129
+ const traceDescription = actionDescription.swipe(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY);
130
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
101
131
  }
102
132
 
103
133
  async takeScreenshot(screenshotName) {
104
134
  // TODO this should be moved to a lower-layer handler of this use-case
105
- const resultBase64 = await new ActionInteraction(this._invocationManager, this, new actions.TakeElementScreenshot()).execute();
135
+ const action = new actions.TakeElementScreenshot();
136
+ const traceDescription = actionDescription.takeScreenshot(screenshotName);
137
+ const resultBase64 = await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
106
138
  const filePath = tempfile('detox.element-screenshot.png');
107
139
  await fs.writeFile(filePath, resultBase64, 'base64');
108
140
 
@@ -115,12 +147,16 @@ class NativeElement {
115
147
  }
116
148
 
117
149
  async getAttributes() {
118
- const result = await new ActionInteraction(this._invocationManager, this, new actions.GetAttributes()).execute();
150
+ const action = new actions.GetAttributes();
151
+ const traceDescription = actionDescription.getAttributes();
152
+ const result = await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
119
153
  return JSON.parse(result);
120
154
  }
121
155
 
122
156
  async adjustSliderToPosition(newPosition) {
123
- return await new ActionInteraction(this._invocationManager, this, new actions.AdjustSliderToPosition(newPosition)).execute();
157
+ const action = new actions.AdjustSliderToPosition(newPosition);
158
+ const traceDescription = actionDescription.adjustSliderToPosition(newPosition);
159
+ return await new ActionInteraction(this._invocationManager, this, action, traceDescription).execute();
124
160
  }
125
161
  }
126
162
 
@@ -1,3 +1,4 @@
1
+ const { expectDescription } = require('../../utils/invocationTraceDescriptions');
1
2
  const { MatcherAssertionInteraction } = require('../interactions/native');
2
3
  const matchers = require('../matchers/native');
3
4
 
@@ -19,7 +20,9 @@ class NativeExpectElement extends NativeExpect {
19
20
  }
20
21
 
21
22
  async toBeVisible(pct) {
22
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.VisibleMatcher(pct).not : new matchers.VisibleMatcher(pct)).execute();
23
+ const matcher = new matchers.VisibleMatcher(pct);
24
+ const traceDescription = expectDescription.toBeVisible(pct);
25
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
23
26
  }
24
27
 
25
28
  async toBeNotVisible() {
@@ -27,7 +30,9 @@ class NativeExpectElement extends NativeExpect {
27
30
  }
28
31
 
29
32
  async toExist() {
30
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.ExistsMatcher().not : new matchers.ExistsMatcher()).execute();
33
+ const matcher = new matchers.ExistsMatcher();
34
+ const traceDescription = expectDescription.toExist();
35
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
31
36
  }
32
37
 
33
38
  async toNotExist() {
@@ -35,7 +40,9 @@ class NativeExpectElement extends NativeExpect {
35
40
  }
36
41
 
37
42
  async toHaveText(text) {
38
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.TextMatcher(text).not : new matchers.TextMatcher(text)).execute();
43
+ const matcher = new matchers.TextMatcher(text);
44
+ const traceDescription = expectDescription.toHaveText(text);
45
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
39
46
  }
40
47
 
41
48
  async toNotHaveText(text) {
@@ -43,7 +50,9 @@ class NativeExpectElement extends NativeExpect {
43
50
  }
44
51
 
45
52
  async toHaveLabel(value) {
46
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.LabelMatcher(value).not : new matchers.LabelMatcher(value)).execute();
53
+ const matcher = new matchers.LabelMatcher(value);
54
+ const traceDescription = expectDescription.toHaveLabel(value);
55
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
47
56
  }
48
57
 
49
58
  async toNotHaveLabel(value) {
@@ -51,7 +60,9 @@ class NativeExpectElement extends NativeExpect {
51
60
  }
52
61
 
53
62
  async toHaveId(value) {
54
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.IdMatcher(value).not : new matchers.IdMatcher(value)).execute();
63
+ const matcher = new matchers.IdMatcher(value);
64
+ const traceDescription = expectDescription.toHaveId(value);
65
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
55
66
  }
56
67
 
57
68
  async toNotHaveId(value) {
@@ -59,7 +70,9 @@ class NativeExpectElement extends NativeExpect {
59
70
  }
60
71
 
61
72
  async toHaveValue(value) {
62
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.ValueMatcher(value).not : new matchers.ValueMatcher(value)).execute();
73
+ const matcher = new matchers.ValueMatcher(value);
74
+ const traceDescription = expectDescription.toHaveValue(value);
75
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
63
76
  }
64
77
 
65
78
  async toNotHaveValue(value) {
@@ -67,15 +80,21 @@ class NativeExpectElement extends NativeExpect {
67
80
  }
68
81
 
69
82
  async toHaveToggleValue(value) {
70
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.ToggleMatcher(value).not : new matchers.ToggleMatcher(value)).execute();
83
+ const matcher = new matchers.ToggleMatcher(value);
84
+ const traceDescription = expectDescription.toHaveToggleValue(value);
85
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
71
86
  }
72
87
 
73
88
  async toHaveSliderPosition(value, tolerance = 0) {
74
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.SliderPositionMatcher(value, tolerance).not : new matchers.SliderPositionMatcher(value, tolerance)).execute();
89
+ const matcher = new matchers.SliderPositionMatcher(value, tolerance);
90
+ const traceDescription = expectDescription.toHaveSliderPosition(value, tolerance);
91
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
75
92
  }
76
93
 
77
94
  async toBeFocused() {
78
- return await new MatcherAssertionInteraction(this._invocationManager, this._element, this._notCondition ? new matchers.FocusMatcher().not : new matchers.FocusMatcher()).execute();
95
+ const matcher = new matchers.FocusMatcher();
96
+ const traceDescription = expectDescription.toBeFocused();
97
+ return await new MatcherAssertionInteraction(this._invocationManager, this._element, matcher, this._notCondition, traceDescription).execute();
79
98
  }
80
99
 
81
100
  async toBeNotFocused() {
@@ -1,4 +1,6 @@
1
1
  const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
2
+ const { expectDescription, actionDescription } = require('../../utils/invocationTraceDescriptions');
3
+ const { trace } = require('../../utils/trace');
2
4
  const { ScrollAmountStopAtEdgeAction } = require('../actions/native');
3
5
  const { NativeMatcher } = require('../core/NativeMatcher');
4
6
  const DetoxAssertionApi = require('../espressoapi/DetoxAssertion');
@@ -9,45 +11,50 @@ function call(maybeAFunction) {
9
11
  }
10
12
 
11
13
  class Interaction {
12
- constructor(invocationManager) {
14
+ constructor(invocationManager, traceDescription) {
13
15
  this._call = undefined;
16
+ this._traceDescription = traceDescription;
14
17
  this._invocationManager = invocationManager;
15
18
  }
16
19
 
17
20
  async execute() {
18
- const resultObj = await this._invocationManager.execute(this._call);
19
- return resultObj ? resultObj.result : undefined;
21
+ return trace.invocationCall(this._traceDescription, this._call,
22
+ this._invocationManager.execute(this._call).then((resultObj) => resultObj ? resultObj.result : undefined));
20
23
  }
21
24
  }
22
25
 
23
26
  class ActionInteraction extends Interaction {
24
- constructor(invocationManager, element, action) {
25
- super(invocationManager);
27
+ constructor(invocationManager, element, action, traceDescription) {
28
+ super(invocationManager, traceDescription);
26
29
  this._call = EspressoDetoxApi.perform(call(element._call), action._call);
27
30
  // TODO: move this.execute() here from the caller
28
31
  }
29
32
  }
30
33
 
31
34
  class MatcherAssertionInteraction extends Interaction {
32
- constructor(invocationManager, element, matcher) {
33
- super(invocationManager);
35
+ constructor(invocationManager, element, matcher, notCondition, traceDescription) {
36
+ traceDescription = expectDescription.full(traceDescription, notCondition);
37
+ super(invocationManager, traceDescription);
38
+
39
+ matcher = notCondition ? matcher.not : matcher;
34
40
  this._call = DetoxAssertionApi.assertMatcher(call(element._call), matcher._call.value);
35
41
  // TODO: move this.execute() here from the caller
36
42
  }
37
43
  }
38
44
 
39
45
  class WaitForInteraction extends Interaction {
40
- constructor(invocationManager, element, assertionMatcher) {
41
- super(invocationManager);
46
+ constructor(invocationManager, element, assertionMatcher, expectTraceDescription) {
47
+ super(invocationManager, expectTraceDescription);
42
48
  this._element = element;
43
49
  this._assertionMatcher = assertionMatcher;
44
50
  this._element._selectElementWithMatcher(this._element._originalMatcher);
45
51
  }
46
52
 
47
53
  async withTimeout(timeout) {
48
- if (typeof timeout !== 'number') throw new DetoxRuntimeError(`WaitForInteraction withTimeout argument must be a number, got ${typeof timeout}`);
49
- if (timeout < 0) throw new DetoxRuntimeError('timeout must be larger than 0');
54
+ if (typeof timeout !== 'number') throw new DetoxRuntimeError({ message: `WaitForInteraction withTimeout argument must be a number, got ${typeof timeout}` });
55
+ if (timeout < 0) throw new DetoxRuntimeError({ message: 'timeout must be larger than 0' });
50
56
 
57
+ this._traceDescription = expectDescription.waitForWithTimeout(this._traceDescription, timeout);
51
58
  this._call = DetoxAssertionApi.waitForAssertMatcher(call(this._element._call), this._assertionMatcher._call.value, timeout / 1000);
52
59
  await this.execute();
53
60
  }
@@ -58,20 +65,18 @@ class WaitForInteraction extends Interaction {
58
65
  }
59
66
 
60
67
  class WaitForActionInteractionBase extends Interaction {
61
- constructor(invocationManager, element, matcher, searchMatcher) {
62
- super(invocationManager);
63
- //if (!(element instanceof NativeElement)) throw new DetoxRuntimeError(`WaitForActionInteraction ctor 1st argument must be a valid NativeElement, got ${typeof element}`);
64
- //if (!(matcher instanceof NativeMatcher)) throw new DetoxRuntimeError(`WaitForActionInteraction ctor 2nd argument must be a valid NativeMatcher, got ${typeof matcher}`);
68
+ constructor(invocationManager, element, matcher, searchMatcher, traceDescription) {
69
+ super(invocationManager, traceDescription);
70
+
65
71
  if (!(searchMatcher instanceof NativeMatcher))
66
- throw new DetoxRuntimeError(`WaitForActionInteraction ctor 3rd argument must be a valid NativeMatcher, got ${typeof searchMatcher}`);
72
+ throw new DetoxRuntimeError({ message: `WaitForActionInteraction ctor 3rd argument must be a valid NativeMatcher, got ${typeof searchMatcher}` });
73
+
67
74
  this._element = element;
68
75
  this._originalMatcher = matcher;
69
76
  this._searchMatcher = searchMatcher;
70
77
  }
71
78
 
72
79
  _prepare(searchAction) {
73
- //if (!searchAction instanceof Action) throw new DetoxRuntimeError(`WaitForActionInteraction _execute argument must be a valid Action, got ${typeof searchAction}`);
74
-
75
80
  this._call = DetoxAssertionApi.waitForAssertMatcherWithSearchAction(
76
81
  call(this._element._call),
77
82
  call(this._originalMatcher._call).value,
@@ -83,6 +88,7 @@ class WaitForActionInteractionBase extends Interaction {
83
88
 
84
89
  class WaitForActionInteraction extends WaitForActionInteractionBase {
85
90
  async scroll(amount, direction = 'down', scrollPositionX, scrollPositionY) {
91
+ this._traceDescription = expectDescription.waitFor(actionDescription.scroll(amount, direction, scrollPositionX, scrollPositionY));
86
92
  this._prepare(new ScrollAmountStopAtEdgeAction(direction, amount, scrollPositionX, scrollPositionY));
87
93
  await this.execute();
88
94
  }
@@ -1,14 +1,13 @@
1
1
  const EventEmitter = require('events');
2
2
  const path = require('path');
3
- const util = require('util');
4
3
 
5
4
  const fs = require('fs-extra');
6
5
  const _ = require('lodash');
7
6
 
8
7
  const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
9
- const log = require('../utils/logger').child({ __filename });
8
+ const log = require('../utils/logger').child({ cat: 'artifacts-manager,artifact' });
10
9
  const resolveModuleFromPath = require('../utils/resolveModuleFromPath');
11
- const { traceMethods } = require('../utils/trace');
10
+ const traceMethods = require('../utils/traceMethods');
12
11
 
13
12
  const FileArtifact = require('./templates/artifact/FileArtifact');
14
13
  const ArtifactPathBuilder = require('./utils/ArtifactPathBuilder');
@@ -23,7 +22,7 @@ class ArtifactsManager extends EventEmitter {
23
22
  this._artifactPlugins = {};
24
23
  this._pathBuilder = this._resolveArtifactsPathBuilder(pathBuilder, rootDir);
25
24
 
26
- traceMethods(this, 'artifacts-manager,artifacts', [
25
+ traceMethods(log, this, [
27
26
  'onAppReady',
28
27
  'onBeforeCleanup',
29
28
  'onBeforeLaunchApp',
@@ -228,27 +227,21 @@ class ArtifactsManager extends EventEmitter {
228
227
  }
229
228
 
230
229
  async _callSinglePlugin(pluginId, methodName, ...args) {
231
- const callSignature = this._composeCallSignature('artifactsManager', methodName, args);
232
- log.trace(Object.assign({ event: 'ARTIFACTS_LIFECYCLE', fn: methodName }, ...args), callSignature);
233
-
234
230
  const plugin = this._artifactPlugins[pluginId];
235
231
  try {
236
232
  await plugin[methodName](...args);
237
233
  } catch (e) {
238
- this._unhandledPluginExceptionHandler(e, { plugin, methodName, args });
234
+ this._unhandledPluginExceptionHandler(e, { plugin, methodName });
239
235
  }
240
236
  }
241
237
 
242
238
  async _callPlugins(strategy, methodName, ...args) {
243
- const callSignature = this._composeCallSignature('artifactsManager', methodName, args);
244
- log.trace(Object.assign({ event: 'ARTIFACTS_LIFECYCLE', fn: methodName }, ...args), callSignature);
245
-
246
239
  for (const pluginGroup of this._groupPlugins(strategy)) {
247
240
  await Promise.all(pluginGroup.map(async (plugin) => {
248
241
  try {
249
242
  await plugin[methodName](...args);
250
243
  } catch (e) {
251
- this._unhandledPluginExceptionHandler(e, { plugin, methodName, args });
244
+ this._unhandledPluginExceptionHandler(e, { plugin, methodName });
252
245
  }
253
246
  }));
254
247
  }
@@ -278,28 +271,20 @@ class ArtifactsManager extends EventEmitter {
278
271
  }
279
272
  }
280
273
 
281
- _composeCallSignature(object, methodName, args) {
282
- const argsString = args.map(arg => util.inspect(arg)).join(', ');
283
- return `${object}.${methodName}(${argsString})`;
284
- }
285
-
286
- _unhandledPluginExceptionHandler(err, { plugin, methodName, args }) {
274
+ _unhandledPluginExceptionHandler(err, { plugin, methodName }) {
287
275
  const logObject = {
288
- event: 'ERROR',
289
276
  plugin: plugin.name,
290
- err,
291
277
  methodName,
278
+ err,
292
279
  };
293
280
 
294
- const callSignature = this._composeCallSignature(plugin.name, methodName, args);
295
- log.warn(logObject, `Suppressed error inside function call: ${callSignature}`);
281
+ log.warn(logObject, `Suppressed error inside function call.`);
296
282
  }
297
283
 
298
284
  _idleCallbackErrorHandle(err, caller) {
299
285
  this._unhandledPluginExceptionHandler(err, {
300
286
  plugin: caller,
301
287
  methodName: 'onIdleCallback',
302
- args: []
303
288
  });
304
289
  }
305
290
  }
@@ -2,7 +2,7 @@
2
2
  const fs = require('fs-extra');
3
3
  const _ = require('lodash');
4
4
 
5
- const log = require('../../../utils/logger').child({ __filename });
5
+ const log = require('../../../utils/logger').child({ cat: 'artifact' });
6
6
  const FileArtifact = require('../../templates/artifact/FileArtifact');
7
7
  const InstrumentsArtifactRecording = require('../InstrumentsArtifactRecording');
8
8
 
@@ -37,9 +37,9 @@ class SimulatorInstrumentsRecording extends InstrumentsArtifactRecording {
37
37
  SimulatorInstrumentsRecording.hintAboutDetoxInstruments = _.once(() => {
38
38
  log.warn(`Make sure either:
39
39
  1. You have installed Detox Instruments:
40
- https://github.com/wix/DetoxInstruments#installation
40
+ https://github.com/wix/DetoxInstruments#installation
41
41
  2. You have integrated Detox Instruments in your app:
42
- https://github.com/wix/DetoxInstruments/blob/master/Documentation/XcodeIntegrationGuide.md
42
+ https://github.com/wix/DetoxInstruments/blob/master/Documentation/XcodeIntegrationGuide.md
43
43
  3. You have set the environment variable with your custom Detox Instruments location:
44
44
  export DETOX_INSTRUMENTS_PATH="/path/to/Detox Instruments.app"`);
45
45
  });
@@ -2,7 +2,7 @@
2
2
  const fs = require('fs-extra');
3
3
 
4
4
  const childProcess = require('../../../utils/childProcess');
5
- const log = require('../../../utils/logger').child({ __filename });
5
+ const log = require('../../../utils/logger').child({ cat: 'artifact' });
6
6
  const sleep = require('../../../utils/sleep');
7
7
  const Artifact = require('../../templates/artifact/Artifact');
8
8
  const FileArtifact = require('../../templates/artifact/FileArtifact');
@@ -1,7 +1,7 @@
1
1
  const path = require('path');
2
2
 
3
3
  const fs = require('../../utils/fsext');
4
- const log = require('../../utils/logger').child({ __filename });
4
+ const log = require('../../utils/logger').child({ cat: 'artifacts-plugin,artifacts' });
5
5
  const FileArtifact = require('../templates/artifact/FileArtifact');
6
6
  const temporaryPath = require('../utils/temporaryPath');
7
7
 
@@ -1,5 +1,5 @@
1
1
  // @ts-nocheck
2
- const log = require('../../../utils/logger').child({ __filename });
2
+ const log = require('../../../utils/logger').child({ cat: 'artifact' });
3
3
 
4
4
  class Artifact {
5
5
  constructor(template) {
@@ -3,7 +3,7 @@
3
3
 
4
4
  const _ = require('lodash');
5
5
 
6
- const log = require('../../../utils/logger').child({ __filename });
6
+ const log = require('../../../utils/logger').child({ cat: 'artifacts-plugin,artifacts' });
7
7
 
8
8
  /***
9
9
  * Almost non-opinionated building block for any artifact type
@@ -0,0 +1,7 @@
1
+ const TIMELINE_CONTEXT_TYPES = {
2
+ TEST: 'test',
3
+ DESCRIBE: 'describe',
4
+ INVOCATION: 'invocation'
5
+ };
6
+
7
+ module.exports = TIMELINE_CONTEXT_TYPES;
@@ -2,15 +2,26 @@ const path = require('path');
2
2
 
3
3
  const tempfile = require('tempfile');
4
4
 
5
+ function createTempFileBuilderFn(fileExtension) {
6
+ /**
7
+ * @param {string} [basename]
8
+ */
9
+ return (basename) => {
10
+ return basename
11
+ ? path.join(path.dirname(tempfile()), `${basename}.detox.${fileExtension}`)
12
+ : tempfile(`.detox.${fileExtension}`);
13
+ };
14
+ }
15
+
5
16
  module.exports = {
6
17
  for: {
7
- json: () => tempfile('.detox.json'),
8
- jsonl: () => tempfile('.detox.jsonl'),
9
- png: () => tempfile('.detox.png'),
10
- log: () => tempfile('.detox.log'),
11
- mp4: () => tempfile('.detox.mp4'),
12
- dtxrec: () => tempfile('.detox.dtxrec'),
13
- viewhierarchy: () => tempfile('.detox.viewhierarchy'),
18
+ json: createTempFileBuilderFn('json'),
19
+ jsonl: createTempFileBuilderFn('jsonl'),
20
+ png: createTempFileBuilderFn('png'),
21
+ log: createTempFileBuilderFn('log'),
22
+ mp4: createTempFileBuilderFn('mp4'),
23
+ dtxrec: createTempFileBuilderFn('dtxrec'),
24
+ viewhierarchy: createTempFileBuilderFn('viewhierarchy'),
14
25
  },
15
26
  mask: () => path.join(tempfile(), '..') + path.sep + '*.detox.*',
16
27
  };
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs-extra');
2
2
 
3
3
  const { interruptProcess } = require('../../utils/childProcess');
4
- const log = require('../../utils/logger').child({ __filename });
4
+ const log = require('../../utils/logger').child({ cat: 'artifacts-plugin,artifact' });
5
5
  const Artifact = require('../templates/artifact/Artifact');
6
6
  const FileArtifact = require('../templates/artifact/FileArtifact');
7
7
  const temporaryPath = require('../utils/temporaryPath');
@@ -5,25 +5,16 @@ const WebSocket = require('ws');
5
5
  const DetoxInternalError = require('../errors/DetoxInternalError');
6
6
  const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
7
7
  const Deferred = require('../utils/Deferred');
8
- const log = require('../utils/logger').child({ __filename, cat: 'ws-client,ws' });
8
+ const log = require('../utils/logger').child({ cat: 'ws-client,ws' });
9
9
 
10
10
  const InflightRequest = require('./InflightRequest');
11
11
 
12
- const EVENTS = {
13
- OPEN: Object.freeze({ event: 'WS_OPEN' }),
14
- ERROR: Object.freeze({ event: 'WS_ERROR' }),
15
- MESSAGE: Object.freeze({ event: 'WS_MESSAGE' }),
16
- SEND: Object.freeze({ event: 'WS_SEND' }),
17
- LATE_RESPONSE: Object.freeze({ event: 'WS_LATE_RESPONSE' }),
18
- };
19
-
20
12
  const DEFAULT_SEND_OPTIONS = {
21
13
  timeout: 0,
22
14
  };
23
15
 
24
16
  class AsyncWebSocket {
25
17
  constructor(url) {
26
- this._log = log.child({ url });
27
18
  this._url = url;
28
19
  this._ws = null;
29
20
  this._eventCallbacks = {};
@@ -99,9 +90,9 @@ class AsyncWebSocket {
99
90
 
100
91
  this.handleMultipleNonAtomicPendingActions();
101
92
 
102
- const messageAsString = JSON.stringify(message);
103
- this._log.trace(EVENTS.SEND, messageAsString);
104
- this._ws.send(messageAsString);
93
+ const payload = JSON.stringify(message);
94
+ log.trace({ data: payload }, 'send message');
95
+ this._ws.send(payload);
105
96
 
106
97
  return inFlight.promise;
107
98
  }
@@ -157,7 +148,7 @@ class AsyncWebSocket {
157
148
  }
158
149
 
159
150
  if (!hasPendingActions) {
160
- log.error(EVENTS.ERROR, DetoxRuntimeError.format(error));
151
+ log.error({ error });
161
152
  }
162
153
  }
163
154
 
@@ -186,7 +177,7 @@ class AsyncWebSocket {
186
177
  * @private
187
178
  */
188
179
  _onOpen(event) { // eslint-disable-line no-unused-vars
189
- this._log.trace(EVENTS.OPEN, `opened web socket to: ${this._url}`);
180
+ log.trace(`opened web socket to: ${this._url}`);
190
181
  this._opening.resolve();
191
182
  this._opening = null;
192
183
  }
@@ -234,7 +225,7 @@ class AsyncWebSocket {
234
225
  const data = event && event.data || null;
235
226
 
236
227
  try {
237
- this._log.trace(EVENTS.MESSAGE, data);
228
+ log.trace({ data }, 'get message');
238
229
 
239
230
  const json = JSON.parse(data);
240
231
  if (!json || !json.type) {
@@ -259,7 +250,7 @@ class AsyncWebSocket {
259
250
 
260
251
  if (!handled) {
261
252
  if (this._abortedMessageIds.has(json.messageId)) {
262
- log.debug(EVENTS.LATE_RESPONSE, `Received late response for messageId=${json.messageId}`);
253
+ log.debug({ messageId: json.messageId }, `late response`);
263
254
  } else {
264
255
  throw new DetoxRuntimeError('Unexpected message received over the web socket: ' + json.type);
265
256
  }