detox 19.10.0 → 19.12.1-prerelease.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. package/Detox-android/com/wix/detox/{19.10.0/detox-19.10.0-javadoc.jar → 19.12.1-prerelease.0/detox-19.12.1-prerelease.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{19.10.0/detox-19.10.0-sources.jar → 19.12.1-prerelease.0/detox-19.12.1-prerelease.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{19.10.0/detox-19.10.0.pom → 19.12.1-prerelease.0/detox-19.12.1-prerelease.0.pom} +1 -7
  17. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-prerelease.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/19.12.1-prerelease.0/detox-19.12.1-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/build.gradle +12 -6
  29. package/android/detox/build.gradle +13 -9
  30. package/android/detox/publishing.gradle +27 -27
  31. package/android/detox/src/full/java/com/wix/detox/LaunchArgs.java +9 -0
  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/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +7 -27
  35. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +1 -11
  36. package/android/detox/src/main/java/com/wix/detox/common/TextFileReader.kt +1 -1
  37. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/DetoxMultiTapSpec.kt +4 -3
  38. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +3 -11
  39. package/package.json +3 -3
  40. package/runners/jest-circus/listeners/DetoxCoreListener.js +24 -16
  41. package/src/DetoxExportWrapper.js +1 -1
  42. package/src/android/core/NativeElement.js +56 -20
  43. package/src/android/core/NativeExpect.js +28 -9
  44. package/src/android/interactions/native.js +24 -18
  45. package/src/artifacts/timeline/TimelineArtifactPlugin.js +6 -9
  46. package/src/artifacts/timeline/TimelineContextTypes.js +7 -0
  47. package/src/devices/allocation/DeviceAllocator.js +1 -2
  48. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +1 -1
  49. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +1 -2
  50. package/src/devices/runtime/RuntimeDevice.js +7 -11
  51. package/src/ios/expectTwo.js +152 -67
  52. package/src/utils/invocationTraceDescriptions.js +43 -0
  53. package/src/utils/trace.js +52 -10
  54. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-javadoc.jar.md5 +0 -1
  55. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-javadoc.jar.sha1 +0 -1
  56. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-javadoc.jar.sha256 +0 -1
  57. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-javadoc.jar.sha512 +0 -1
  58. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-sources.jar.md5 +0 -1
  59. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-sources.jar.sha1 +0 -1
  60. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-sources.jar.sha256 +0 -1
  61. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0-sources.jar.sha512 +0 -1
  62. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.aar +0 -0
  63. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.aar.md5 +0 -1
  64. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.aar.sha1 +0 -1
  65. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.aar.sha256 +0 -1
  66. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.aar.sha512 +0 -1
  67. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.pom.md5 +0 -1
  68. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.pom.sha1 +0 -1
  69. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.pom.sha256 +0 -1
  70. package/Detox-android/com/wix/detox/19.10.0/detox-19.10.0.pom.sha512 +0 -1
  71. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategy.kt +0 -84
  72. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DefaultIdleInterrogationStrategySpec.kt +0 -115
@@ -11,6 +11,7 @@ import org.assertj.core.api.Assertions.assertThat
11
11
  import org.mockito.kotlin.*
12
12
  import org.spekframework.spek2.Spek
13
13
  import org.spekframework.spek2.style.specification.describe
14
+ import java.lang.NullPointerException
14
15
  import kotlin.test.assertFailsWith
15
16
 
16
17
  object DetoxMultiTapSpec: Spek({
@@ -136,17 +137,17 @@ object DetoxMultiTapSpec: Spek({
136
137
  }
137
138
 
138
139
  it("should throw if no UI-controller provided") {
139
- assertFailsWith(KotlinNullPointerException::class) {
140
+ assertFailsWith(NullPointerException::class) {
140
141
  uut(1).sendTap(null, coordinates, precision, -1, -1)
141
142
  }
142
143
  }
143
144
 
144
145
  it("should throw if no coordinates / precision are provided") {
145
- assertFailsWith(KotlinNullPointerException::class) {
146
+ assertFailsWith(NullPointerException::class) {
146
147
  uut(1).sendTap(uiController, null, precision, -1, -1)
147
148
  }
148
149
 
149
- assertFailsWith(KotlinNullPointerException::class) {
150
+ assertFailsWith(NullPointerException::class) {
150
151
  uut(1).sendTap(uiController, coordinates, null, -1, -1)
151
152
  }
152
153
  }
@@ -5,22 +5,14 @@ import org.assertj.core.api.Assertions.assertThat
5
5
  import org.mockito.kotlin.*
6
6
  import org.spekframework.spek2.Spek
7
7
  import org.spekframework.spek2.style.specification.describe
8
+ import com.facebook.react.modules.core.TimingModule
8
9
 
9
10
  private const val BUSY_INTERVAL_MS = 1500L
10
11
 
11
- abstract class TimingModuleStub: NativeModule {
12
- abstract fun hasActiveTimersInRange(rangeMs: Long): Boolean
13
-
14
- override fun onCatalystInstanceDestroy() {}
15
- override fun getName(): String = "TimersNativeModuleStub"
16
- override fun canOverrideExistingModule() = false
17
- override fun initialize() {}
18
- }
19
-
20
12
  object DelegatedIdleInterrogationStrategySpec : Spek({
21
- describe("RN62+ timers idle-interrogation strategy") {
13
+ describe("Timers idle-interrogation strategy") {
22
14
 
23
- lateinit var timingModule: TimingModuleStub
15
+ lateinit var timingModule: TimingModule
24
16
 
25
17
  beforeEachTest {
26
18
  timingModule = mock()
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": "19.10.0",
4
+ "version": "19.12.1-prerelease.0",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -47,7 +47,7 @@
47
47
  "mocha": ">=6.0.0",
48
48
  "mockdate": "^2.0.1",
49
49
  "prettier": "1.7.0",
50
- "react-native": "0.68.2",
50
+ "react-native": "0.69.5",
51
51
  "react-native-codegen": "^0.0.8",
52
52
  "typescript": "^4.5.2",
53
53
  "wtfnode": "^0.9.1"
@@ -177,5 +177,5 @@
177
177
  }
178
178
  }
179
179
  },
180
- "gitHead": "6468b38c68bcac4c283ef005e9817f1d7ba8161b"
180
+ "gitHead": "94efae8dfa967f02285c28b3da18e305bd8a0e9c"
181
181
  }
@@ -22,16 +22,6 @@ class DetoxCoreListener {
22
22
  this.detox = detox;
23
23
  }
24
24
 
25
- _getTestInvocations(test) {
26
- const { DETOX_RERUN_INDEX } = process.env;
27
-
28
- if (!isNaN(DETOX_RERUN_INDEX)) {
29
- return Number(DETOX_RERUN_INDEX) * this._testRunTimes + test.invocations;
30
- } else {
31
- return test.invocations;
32
- }
33
- }
34
-
35
25
  async run_describe_start({ describeBlock: { name, children } }) {
36
26
  if (children.length) {
37
27
  await this.detox[onRunDescribeStart]({ name });
@@ -80,20 +70,38 @@ class DetoxCoreListener {
80
70
  this._startedTests.add(test);
81
71
 
82
72
  await this.detox[onTestStart]({
73
+ ...this._getTestMetadata(test),
74
+ status: 'running',
75
+ });
76
+ }
77
+
78
+ _getTestMetadata(test) {
79
+ return {
83
80
  title: test.name,
81
+ parent: test.parent.name,
84
82
  fullName: getFullTestName(test),
85
- status: 'running',
83
+ functionCode: test.fn.toString(),
86
84
  invocations: this._getTestInvocations(test),
87
- });
85
+ };
86
+ }
87
+
88
+ _getTestInvocations(test) {
89
+ const { DETOX_RERUN_INDEX } = process.env;
90
+
91
+ if (!isNaN(DETOX_RERUN_INDEX)) {
92
+ return Number(DETOX_RERUN_INDEX) * this._testRunTimes + test.invocations;
93
+ } else {
94
+ return test.invocations;
95
+ }
88
96
  }
89
97
 
90
98
  async test_done({ test }) {
91
99
  if (this._startedTests.has(test)) {
92
100
  await this.detox[onTestDone]({
93
- title: test.name,
94
- fullName: getFullTestName(test),
95
- status: test.errors.length ? 'failed' : 'passed',
96
- invocations: this._getTestInvocations(test),
101
+ ...this._getTestMetadata(test),
102
+ status: _.isEmpty(test.errors) ? 'passed' : 'failed',
103
+ errors: _.isEmpty(test.errors) ? undefined : test.errors,
104
+ asyncError: _.isEmpty(test.asyncError) ? undefined : test.asyncError,
97
105
  timedOut: hasTimedOut(test)
98
106
  });
99
107
 
@@ -66,7 +66,7 @@ class DetoxExportWrapper {
66
66
  }
67
67
 
68
68
  this[_detox] = new Detox(resolvedConfig);
69
- await traceCall('detoxInit', () => this[_detox].init());
69
+ await traceCall('detoxInit', this[_detox].init());
70
70
  Detox.none.setError(null);
71
71
 
72
72
  return this[_detox];
@@ -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 { traceInvocationCall } = 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 traceInvocationCall(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
  }
@@ -7,16 +7,13 @@ const { trace } = require('../../utils/trace');
7
7
  const FileArtifact = require('../templates/artifact/FileArtifact');
8
8
  const ArtifactPlugin = require('../templates/plugin/ArtifactPlugin');
9
9
 
10
+ const TIMELINE_CONTEXT_TYPES = require('./TimelineContextTypes');
11
+
10
12
  const traceNoop = {
11
13
  startSection: _noop,
12
14
  endSection: _noop,
13
15
  };
14
16
 
15
- const CONTEXT_TYPES = {
16
- TEST: 'test',
17
- DESCRIBE: 'describe'
18
- };
19
-
20
17
  class TimelineArtifactPlugin extends ArtifactPlugin {
21
18
  constructor(config) {
22
19
  super(config);
@@ -37,23 +34,23 @@ class TimelineArtifactPlugin extends ArtifactPlugin {
37
34
 
38
35
  async onRunDescribeStart(suite) {
39
36
  const sectionName = (suite.name === 'ROOT_DESCRIBE_BLOCK' ? this._deviceName : suite.name);
40
- this._trace.startSection(sectionName, { context: CONTEXT_TYPES.DESCRIBE });
37
+ this._trace.startSection(sectionName, { context: TIMELINE_CONTEXT_TYPES.DESCRIBE });
41
38
  await super.onRunDescribeStart(suite);
42
39
  }
43
40
 
44
41
  async onRunDescribeFinish(suite) {
45
42
  const sectionName = (suite.name === 'ROOT_DESCRIBE_BLOCK' ? this._deviceName : suite.name);
46
- this._trace.endSection(sectionName, { context: CONTEXT_TYPES.DESCRIBE });
43
+ this._trace.endSection(sectionName, { context: TIMELINE_CONTEXT_TYPES.DESCRIBE });
47
44
  await super.onRunDescribeFinish(suite);
48
45
  }
49
46
 
50
47
  async onTestStart(testSummary) {
51
- this._trace.startSection(testSummary.title, { context: CONTEXT_TYPES.TEST });
48
+ this._trace.startSection(testSummary.title, { context: TIMELINE_CONTEXT_TYPES.TEST, ...testSummary });
52
49
  await super.onTestStart(testSummary);
53
50
  }
54
51
 
55
52
  async onTestDone(testSummary) {
56
- this._trace.endSection(testSummary.title, { status: testSummary.status, context: CONTEXT_TYPES.TEST });
53
+ this._trace.endSection(testSummary.title, { context: TIMELINE_CONTEXT_TYPES.TEST, ...testSummary });
57
54
  await super.onTestDone(testSummary);
58
55
  }
59
56
 
@@ -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;
@@ -14,8 +14,7 @@ class DeviceAllocator {
14
14
  * @return {Promise<DeviceCookie>}
15
15
  */
16
16
  allocate(deviceConfig) {
17
- return traceCall('allocateDevice', () =>
18
- this._driver.allocate(deviceConfig));
17
+ return traceCall('allocateDevice', this._driver.allocate(deviceConfig));
19
18
  }
20
19
 
21
20
  /**
@@ -73,7 +73,7 @@ class EmulatorAllocDriver extends AllocationDriverBase {
73
73
 
74
74
  async _launchEmulator(avdName, adbName, isRunning, options) {
75
75
  try {
76
- await traceCall('emulatorLaunch', () =>
76
+ await traceCall('emulatorLaunch',
77
77
  this._emulatorLauncher.launch(avdName, adbName, isRunning, options));
78
78
  } catch (e) {
79
79
  await this._allocationHelper.deallocateDevice(adbName);
@@ -63,8 +63,7 @@ class EmulatorLauncher extends DeviceLauncher {
63
63
  }
64
64
 
65
65
  async _awaitEmulatorBoot(adbName) {
66
- await traceCall('awaitBoot', () =>
67
- this._waitForBootToComplete(adbName));
66
+ await traceCall('awaitBoot', this._waitForBootToComplete(adbName));
68
67
  }
69
68
 
70
69
  async _waitForBootToComplete(adbName) {
@@ -113,7 +113,7 @@ class RuntimeDevice {
113
113
  }
114
114
 
115
115
  async launchApp(params = {}, bundleId = this._bundleId) {
116
- return traceCall('launchApp', () => this._doLaunchApp(params, bundleId));
116
+ return traceCall('launch app', this._doLaunchApp(params, bundleId));
117
117
  }
118
118
 
119
119
  /**
@@ -179,29 +179,25 @@ class RuntimeDevice {
179
179
  }
180
180
 
181
181
  async installApp(binaryPath, testBinaryPath) {
182
- await traceCall('appInstall', () => {
183
- const currentApp = binaryPath ? { binaryPath, testBinaryPath } : this._getCurrentApp();
184
- return this.deviceDriver.installApp(currentApp.binaryPath, currentApp.testBinaryPath);
185
- });
182
+ const currentApp = binaryPath ? { binaryPath, testBinaryPath } : this._getCurrentApp();
183
+ await traceCall('appInstall',
184
+ this.deviceDriver.installApp(currentApp.binaryPath, currentApp.testBinaryPath));
186
185
  }
187
186
 
188
187
  async uninstallApp(bundleId) {
189
188
  const _bundleId = bundleId || this._bundleId;
190
- await traceCall('appUninstall', () =>
191
- this.deviceDriver.uninstallApp(_bundleId));
189
+ await traceCall('appUninstall', this.deviceDriver.uninstallApp(_bundleId));
192
190
  }
193
191
 
194
192
  async installUtilBinaries() {
195
193
  const paths = this._deviceConfig.utilBinaryPaths;
196
194
  if (paths) {
197
- await traceCall('installUtilBinaries', () =>
198
- this.deviceDriver.installUtilBinaries(paths));
195
+ await traceCall('installUtilBinaries', this.deviceDriver.installUtilBinaries(paths));
199
196
  }
200
197
  }
201
198
 
202
199
  async reloadReactNative() {
203
- await traceCall('reloadRN', () =>
204
- this.deviceDriver.reloadReactNative());
200
+ await traceCall('reload React Native', this.deviceDriver.reloadReactNative());
205
201
  }
206
202
 
207
203
  async openURL(params) {