detox 20.14.10-smoke.1 → 20.15.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.js +0 -4
- package/Detox-android/com/wix/detox/{20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar → 20.15.0/detox-20.15.0-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar → 20.15.0/detox-20.15.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.14.10-smoke.1/detox-20.14.10-smoke.1.pom → 20.15.0/detox-20.15.0.pom} +1 -1
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.15.0/detox-20.15.0.pom.sha512 +1 -0
- package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
- package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios.tbz +0 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +11 -6
- package/android/detox/src/main/java/com/wix/detox/espresso/DeviceDisplay.kt +1 -1
- package/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java +113 -16
- package/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/ScrollHelperTest.kt +188 -0
- package/detox.d.ts +5 -2
- package/package.json +2 -2
- package/src/android/actions/native.js +2 -2
- package/src/android/core/NativeElement.js +3 -4
- package/src/android/espressoapi/DetoxAction.js +9 -1
- package/src/android/interactions/native.js +2 -2
- package/src/android/matchers/native.js +1 -1
- package/src/artifacts/providers/index.js +1 -1
- package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +0 -1
- package/src/artifacts/templates/artifact/Artifact.js +1 -1
- package/src/client/AsyncWebSocket.js +2 -2
- package/src/client/Client.js +2 -2
- package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +0 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +0 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +1 -1
- package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +0 -1
- package/src/devices/allocation/factories/android.js +1 -1
- package/src/devices/allocation/factories/ios.js +1 -1
- package/src/devices/common/drivers/android/exec/ADB.js +1 -2
- package/src/devices/common/drivers/android/tools/AppInstallHelper.js +0 -2
- package/src/devices/runtime/drivers/android/emulator/EmulatorDriver.js +0 -1
- package/src/devices/runtime/factories/ios.js +0 -2
- package/src/ios/expectTwo.js +6 -3
- package/src/ipc/IPCServer.js +1 -1
- package/src/realms/DetoxPrimaryContext.js +0 -3
- package/src/utils/invocationTraceDescriptions.js +3 -2
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.aar +0 -0
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1.pom.sha512 +0 -1
package/.eslintrc.js
CHANGED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
6af6a1128b61c579b4a5c82d2865f585
|
@@ -0,0 +1 @@
|
|
1
|
+
4dba1aa3f352698d234cccc7f69d8d3e69350458
|
@@ -0,0 +1 @@
|
|
1
|
+
0d73e6570afca6e11cefdb63125dd01bdd0f33143089402c752c506b5acf85a3
|
@@ -0,0 +1 @@
|
|
1
|
+
cda5ab07eac2a8371056647e4b6391a1c42e2d4a5b1a6a7a810a398ed4f29946441ea9da132a236cee7e523b09b6b6ea8f1510e5faaec0061193c84767e1d849
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
b912691ddb7318d42de9431f7435bc9a
|
@@ -0,0 +1 @@
|
|
1
|
+
5c90afac3b3a7d5fa2ba83e650604f6f9bc00682
|
@@ -0,0 +1 @@
|
|
1
|
+
5eabd613ae0284bc97755f7e29cf0d233e281ae7635afeeb0875437401c3ddb8
|
@@ -0,0 +1 @@
|
|
1
|
+
5ef628faf38474b46638efc54f932b15824f5735497279f0153fe9c6afc2f7de9a151ee46e51724ce93ff22515bf43b86147f8330c67a49b34dd45ce3b129c5d
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
8a77aaff1489b4887d6873aaae1357a3
|
@@ -0,0 +1 @@
|
|
1
|
+
d5f06bdfb31d314d08ef800ab5d9148502702d2a
|
@@ -0,0 +1 @@
|
|
1
|
+
7f45586ecc61fe0f158c8701000529d566299aa4b24f9539e4cc4ea2d29d898e
|
@@ -0,0 +1 @@
|
|
1
|
+
b00a7385379509967eb9ffed2c619e19008f03fc2d5534fb80bd08c31a6f9d937d9269858a4f3d03878d4979259d43da7ccec3173954454ff50c9a18590f1d20
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
4
4
|
<groupId>com.wix</groupId>
|
5
5
|
<artifactId>detox</artifactId>
|
6
|
-
<version>20.
|
6
|
+
<version>20.15.0</version>
|
7
7
|
<packaging>aar</packaging>
|
8
8
|
<name>Detox</name>
|
9
9
|
<description>Gray box end-to-end testing and automation library for mobile apps</description>
|
@@ -0,0 +1 @@
|
|
1
|
+
b214c6ec949dbb966c2ab104243efbb5
|
@@ -0,0 +1 @@
|
|
1
|
+
91c5ac02c59420f8a6eaca4af5fa5a5d40901b92
|
@@ -0,0 +1 @@
|
|
1
|
+
8e39181294f58719e0d42ea4b6220526012c229b47ab6db988acd904a8bba64c
|
@@ -0,0 +1 @@
|
|
1
|
+
c919a336c80ca89a3d41975a6b8574539f93234105f7762870afdd1540ef44763b00ecf7860b6cb22457ff9c714047f5c78f9a341c9ad923fc8beb25fd1d1331
|
@@ -3,11 +3,11 @@
|
|
3
3
|
<groupId>com.wix</groupId>
|
4
4
|
<artifactId>detox</artifactId>
|
5
5
|
<versioning>
|
6
|
-
<latest>20.
|
7
|
-
<release>20.
|
6
|
+
<latest>20.15.0</latest>
|
7
|
+
<release>20.15.0</release>
|
8
8
|
<versions>
|
9
|
-
<version>20.
|
9
|
+
<version>20.15.0</version>
|
10
10
|
</versions>
|
11
|
-
<lastUpdated>
|
11
|
+
<lastUpdated>20240111111712</lastUpdated>
|
12
12
|
</versioning>
|
13
13
|
</metadata>
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
9e22bc0ea12d6e5775b68bde874bdf22
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
add0ba9ace5604f9bad42acfe204f32728323ce4
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
8d6d198043d40230347ae63f85625557fd6b2f45494d80c14e19e7e8e2f19fd2
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
7411bfbd2cbeb1e65e91618e520b083f54253f8b5e8f17f8b187de2716d3bf809c45246eb2bca80a9011f439f65f08053442daa846c4833bcb28f378a42e18b6
|
package/Detox-ios-src.tbz
CHANGED
Binary file
|
package/Detox-ios.tbz
CHANGED
Binary file
|
@@ -79,9 +79,14 @@ public class DetoxAction {
|
|
79
79
|
* Scrolls to the edge of the given scrollable view.
|
80
80
|
*
|
81
81
|
* @param edge Direction to scroll (see {@link MotionDir})
|
82
|
+
* @param startOffsetPercentX Percentage denoting where the scroll should start from on the X-axis, with respect to the scrollable view.
|
83
|
+
* @param startOffsetPercentY Percentage denoting where the scroll should start from on the Y-axis, with respect to the scrollable view.
|
82
84
|
* @return ViewAction
|
83
85
|
*/
|
84
|
-
public static ViewAction scrollToEdge(final int edge) {
|
86
|
+
public static ViewAction scrollToEdge(final int edge, double startOffsetPercentX, double startOffsetPercentY) {
|
87
|
+
final Float _startOffsetPercentX = startOffsetPercentX < 0 ? null : (float) startOffsetPercentX;
|
88
|
+
final Float _startOffsetPercentY = startOffsetPercentY < 0 ? null : (float) startOffsetPercentY;
|
89
|
+
|
85
90
|
return actionWithAssertions(new ViewAction() {
|
86
91
|
@Override
|
87
92
|
public Matcher<View> getConstraints() {
|
@@ -97,7 +102,7 @@ public class DetoxAction {
|
|
97
102
|
public void perform(UiController uiController, View view) {
|
98
103
|
try {
|
99
104
|
for (int i = 0; i < 100; i++) {
|
100
|
-
ScrollHelper.performOnce(uiController, view, edge);
|
105
|
+
ScrollHelper.performOnce(uiController, view, edge, _startOffsetPercentX, _startOffsetPercentY);
|
101
106
|
}
|
102
107
|
throw new DetoxRuntimeException("Scrolling a lot without reaching the edge: force-breaking the loop");
|
103
108
|
} catch (ScrollEdgeException e) {
|
@@ -112,8 +117,8 @@ public class DetoxAction {
|
|
112
117
|
*
|
113
118
|
* @param direction Direction to scroll (see {@link MotionDir})
|
114
119
|
* @param amountInDP Density Independent Pixels
|
115
|
-
* @param startOffsetPercentX Percentage denoting where
|
116
|
-
* @param startOffsetPercentY Percentage denoting where
|
120
|
+
* @param startOffsetPercentX Percentage denoting where the scroll should start from on the X-axis, with respect to the scrollable view.
|
121
|
+
* @param startOffsetPercentY Percentage denoting where the scroll should start from on the Y-axis, with respect to the scrollable view.
|
117
122
|
*/
|
118
123
|
public static ViewAction scrollInDirection(final int direction, final double amountInDP, double startOffsetPercentX, double startOffsetPercentY) {
|
119
124
|
final Float _startOffsetPercentX = startOffsetPercentX < 0 ? null : (float) startOffsetPercentX;
|
@@ -129,8 +134,8 @@ public class DetoxAction {
|
|
129
134
|
*
|
130
135
|
* @param direction Direction to scroll (see {@link MotionDir})
|
131
136
|
* @param amountInDP Density Independent Pixels
|
132
|
-
* @param startOffsetPercentX Percentage denoting where
|
133
|
-
* @param startOffsetPercentY Percentage denoting where
|
137
|
+
* @param startOffsetPercentX Percentage denoting where the scroll should start from on the X-axis, with respect to the scrollable view.
|
138
|
+
* @param startOffsetPercentY Percentage denoting where the scroll should start from on the Y-axis, with respect to the scrollable view.
|
134
139
|
*/
|
135
140
|
public static ViewAction scrollInDirectionStaleAtEdge(final int direction, final double amountInDP, double startOffsetPercentX, double startOffsetPercentY) {
|
136
141
|
final Float _startOffsetPercentX = startOffsetPercentX < 0 ? null : (float) startOffsetPercentX;
|
@@ -1,14 +1,18 @@
|
|
1
1
|
package com.wix.detox.espresso.scroll;
|
2
2
|
|
3
3
|
import android.content.Context;
|
4
|
+
import android.graphics.Insets;
|
4
5
|
import android.graphics.Point;
|
6
|
+
import android.os.Build;
|
5
7
|
import android.util.Log;
|
6
8
|
import android.view.View;
|
7
9
|
import android.view.ViewConfiguration;
|
10
|
+
import android.view.WindowInsets;
|
8
11
|
|
9
12
|
import com.wix.detox.action.common.MotionDir;
|
10
13
|
import com.wix.detox.espresso.DeviceDisplay;
|
11
14
|
|
15
|
+
import androidx.annotation.VisibleForTesting;
|
12
16
|
import androidx.test.espresso.UiController;
|
13
17
|
import androidx.test.platform.app.InstrumentationRegistry;
|
14
18
|
|
@@ -42,8 +46,8 @@ public class ScrollHelper {
|
|
42
46
|
*
|
43
47
|
* @param direction Direction to scroll (see {@link MotionDir})
|
44
48
|
* @param amountInDP Density Independent Pixels
|
45
|
-
* @param startOffsetPercentX Percentage denoting where
|
46
|
-
* @param startOffsetPercentY Percentage denoting where
|
49
|
+
* @param startOffsetPercentX Percentage denoting where the scroll should start from on the X-axis, with respect to the scrollable view. Null means select automatically.
|
50
|
+
* @param startOffsetPercentY Percentage denoting where the scroll should start from on the Y-axis, with respect to the scrollable view. Null means select automatically.
|
47
51
|
*/
|
48
52
|
public static void perform(UiController uiController, View view, @MotionDir int direction, double amountInDP, Float startOffsetPercentX, Float startOffsetPercentY) throws ScrollEdgeException {
|
49
53
|
final int amountInPx = DeviceDisplay.convertDpiToPx(amountInDP);
|
@@ -51,7 +55,7 @@ public class ScrollHelper {
|
|
51
55
|
final int times = amountInPx / safeScrollableRangePx;
|
52
56
|
final int remainder = amountInPx % safeScrollableRangePx;
|
53
57
|
|
54
|
-
Log.d(LOG_TAG, "prescroll amountDP="+amountInDP + " amountPx="+amountInPx + " scrollableRangePx="+safeScrollableRangePx + " times="+times + " remainder="+remainder);
|
58
|
+
Log.d(LOG_TAG, "prescroll amountDP=" + amountInDP + " amountPx=" + amountInPx + " scrollableRangePx=" + safeScrollableRangePx + " times=" + times + " remainder=" + remainder);
|
55
59
|
|
56
60
|
for (int i = 0; i < times; ++i) {
|
57
61
|
scrollOnce(uiController, view, direction, safeScrollableRangePx, startOffsetPercentX, startOffsetPercentY);
|
@@ -64,10 +68,12 @@ public class ScrollHelper {
|
|
64
68
|
* of the screen.)
|
65
69
|
*
|
66
70
|
* @param direction Direction to scroll (see {@link @MotionDir})
|
71
|
+
* @param startOffsetPercentX Percentage denoting where the scroll should start from on the X-axis, with respect to the scrollable view. Null means select automatically.
|
72
|
+
* @param startOffsetPercentY Percentage denoting where the scroll should start from on the Y-axis, with respect to the scrollable view. Null means select automatically.
|
67
73
|
*/
|
68
|
-
public static void performOnce(UiController uiController, View view, @MotionDir int direction) throws ScrollEdgeException {
|
74
|
+
public static void performOnce(UiController uiController, View view, @MotionDir int direction, Float startOffsetPercentX, Float startOffsetPercentY) throws ScrollEdgeException {
|
69
75
|
final int scrollableRangePx = getViewSafeScrollableRangePix(view, direction);
|
70
|
-
scrollOnce(uiController, view, direction, scrollableRangePx,
|
76
|
+
scrollOnce(uiController, view, direction, scrollableRangePx, startOffsetPercentX, startOffsetPercentY);
|
71
77
|
}
|
72
78
|
|
73
79
|
private static void scrollOnce(UiController uiController, View view, @MotionDir int direction, int userAmountPx, Float startOffsetPercentX, Float startOffsetPercentY) throws ScrollEdgeException {
|
@@ -113,25 +119,32 @@ public class ScrollHelper {
|
|
113
119
|
}
|
114
120
|
}
|
115
121
|
|
116
|
-
|
122
|
+
@VisibleForTesting
|
123
|
+
public static int getViewSafeScrollableRangePix(View view, @MotionDir int direction) {
|
117
124
|
final float[] screenSize = DeviceDisplay.getScreenSizeInPX();
|
118
125
|
final int[] pos = new int[2];
|
119
126
|
view.getLocationInWindow(pos);
|
120
127
|
|
121
128
|
int range;
|
122
129
|
switch (direction) {
|
123
|
-
case MOTION_DIR_LEFT:
|
124
|
-
|
125
|
-
|
126
|
-
|
130
|
+
case MOTION_DIR_LEFT:
|
131
|
+
range = (int) ((screenSize[0] - pos[0]) * SCROLL_RANGE_SAFE_PERCENT);
|
132
|
+
break;
|
133
|
+
case MOTION_DIR_RIGHT:
|
134
|
+
range = (int) ((pos[0] + view.getWidth()) * SCROLL_RANGE_SAFE_PERCENT);
|
135
|
+
break;
|
136
|
+
case MOTION_DIR_UP:
|
137
|
+
range = (int) ((screenSize[1] - pos[1]) * SCROLL_RANGE_SAFE_PERCENT);
|
138
|
+
break;
|
139
|
+
default:
|
140
|
+
range = (int) ((pos[1] + view.getHeight()) * SCROLL_RANGE_SAFE_PERCENT);
|
141
|
+
break;
|
127
142
|
}
|
128
143
|
return range;
|
129
144
|
}
|
130
145
|
|
131
|
-
private static
|
146
|
+
private static int[] getScrollStartOffsetInView(View view, @MotionDir int direction, Float startOffsetPercentX, Float startOffsetPercentY) {
|
132
147
|
final int safetyOffset = DeviceDisplay.convertDpiToPx(1);
|
133
|
-
|
134
|
-
Point point = getGlobalViewLocation(view);
|
135
148
|
float offsetFactorX;
|
136
149
|
float offsetFactorY;
|
137
150
|
int safetyOffsetX;
|
@@ -169,8 +182,87 @@ public class ScrollHelper {
|
|
169
182
|
int offsetX = ((int) (view.getWidth() * offsetFactorX) + safetyOffsetX);
|
170
183
|
int offsetY = ((int) (view.getHeight() * offsetFactorY) + safetyOffsetY);
|
171
184
|
|
172
|
-
|
173
|
-
|
185
|
+
return new int[]{offsetX, offsetY};
|
186
|
+
}
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Calculates the scroll start point, with respect to the global screen coordinates and gesture insets.
|
190
|
+
* @param view The view to scroll.
|
191
|
+
* @param direction The scroll direction.
|
192
|
+
* @param startOffsetPercentX The scroll start offset, as a percentage of the view's width. Null means select automatically.
|
193
|
+
* @param startOffsetPercentY The scroll start offset, as a percentage of the view's height. Null means select automatically.
|
194
|
+
* @return a Point object, denoting the scroll start point.
|
195
|
+
*/
|
196
|
+
private static Point getScrollStartPoint(View view, @MotionDir int direction, Float startOffsetPercentX, Float startOffsetPercentY) {
|
197
|
+
Point result = getGlobalViewLocation(view);
|
198
|
+
|
199
|
+
// 1. Calculate the scroll start point, with respect to the view's location.
|
200
|
+
int[] coordinates = getScrollStartOffsetInView(view, direction, startOffsetPercentX, startOffsetPercentY);
|
201
|
+
|
202
|
+
// 2. Make sure that the start point is within the scrollable area, taking into account the system gesture insets.
|
203
|
+
coordinates = applyScreenInsets(view, direction, coordinates[0], coordinates[1]);
|
204
|
+
|
205
|
+
result.offset(coordinates[0], coordinates[1]);
|
206
|
+
return result;
|
207
|
+
}
|
208
|
+
|
209
|
+
/**
|
210
|
+
* Calculates the scroll start point, with respect to the system gesture insets.
|
211
|
+
* @param view
|
212
|
+
* @param direction The scroll direction.
|
213
|
+
* @param x The scroll start point, with respect to the view's location.
|
214
|
+
* @param y The scroll start point, with respect to the view's location.
|
215
|
+
* @return an array of two integers, denoting the scroll start point, with respect to the system gesture insets.
|
216
|
+
*/
|
217
|
+
private static int[] applyScreenInsets(View view, int direction, int x, int y) {
|
218
|
+
// System gesture insets are only available on Android Q (29) and above.
|
219
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
220
|
+
return new int[]{x, y};
|
221
|
+
}
|
222
|
+
|
223
|
+
final float[] displaySize = DeviceDisplay.getScreenSizeInPX();
|
224
|
+
|
225
|
+
// Calculate the min/max scrollable area, taking into account the system gesture insets.
|
226
|
+
// By default we assume the scrollable area is the entire screen.
|
227
|
+
// 2dp is a safety offset to make sure we don't hit the system gesture area.
|
228
|
+
int gestureSafeOffset = DeviceDisplay.convertDpiToPx(2);
|
229
|
+
int minX = gestureSafeOffset;
|
230
|
+
int minY = gestureSafeOffset;
|
231
|
+
float maxX = displaySize[0] - gestureSafeOffset;
|
232
|
+
float maxY = displaySize[1] - gestureSafeOffset;
|
233
|
+
|
234
|
+
// Try to get the root window insets, and if available, use them to calculate the scrollable area.
|
235
|
+
WindowInsets rootWindowInsets = view.getRootWindowInsets();
|
236
|
+
if (rootWindowInsets == null) {
|
237
|
+
Log.w(LOG_TAG, "Could not get root window insets");
|
238
|
+
} else {
|
239
|
+
Insets gestureInsets = rootWindowInsets.getSystemGestureInsets();
|
240
|
+
minX = gestureInsets.left;
|
241
|
+
minY = gestureInsets.top;
|
242
|
+
maxX -= gestureInsets.right;
|
243
|
+
maxY -= gestureInsets.bottom;
|
244
|
+
|
245
|
+
Log.d(LOG_TAG,
|
246
|
+
"System gesture insets: " +
|
247
|
+
gestureInsets + " minX=" + minX + " minY=" + minY + " maxX=" + maxX + " maxY=" + maxY + " currentX=" + x + " currentY=" + y);
|
248
|
+
}
|
249
|
+
|
250
|
+
switch (direction) {
|
251
|
+
case MOTION_DIR_UP:
|
252
|
+
y = (int) Math.max(y, minY);
|
253
|
+
break;
|
254
|
+
case MOTION_DIR_DOWN:
|
255
|
+
y = (int) Math.min(y, maxY);
|
256
|
+
break;
|
257
|
+
case MOTION_DIR_LEFT:
|
258
|
+
x = (int) Math.max(x, minX);
|
259
|
+
break;
|
260
|
+
case MOTION_DIR_RIGHT:
|
261
|
+
x = (int) Math.min(x, maxX);
|
262
|
+
break;
|
263
|
+
}
|
264
|
+
|
265
|
+
return new int[]{x, y};
|
174
266
|
}
|
175
267
|
|
176
268
|
private static Point getScrollEndPoint(Point startPoint, @MotionDir int direction, int userAmountPx, Float startOffsetPercentX, Float startOffsetPercentY) {
|
@@ -209,13 +301,18 @@ public class ScrollHelper {
|
|
209
301
|
return point;
|
210
302
|
}
|
211
303
|
|
304
|
+
/**
|
305
|
+
* Calculates the global location of the view on the screen.
|
306
|
+
* @param view The view to calculate.
|
307
|
+
* @return a Point object, denoting the global location of the view.
|
308
|
+
*/
|
212
309
|
private static Point getGlobalViewLocation(View view) {
|
213
310
|
int[] pos = new int[2];
|
214
311
|
view.getLocationInWindow(pos);
|
215
312
|
return new Point(pos[0], pos[1]);
|
216
313
|
}
|
217
314
|
|
218
|
-
|
315
|
+
public static ViewConfiguration getViewConfiguration() {
|
219
316
|
if (viewConfiguration == null) {
|
220
317
|
final Context applicationContext = InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext();
|
221
318
|
viewConfiguration = ViewConfiguration.get(applicationContext);
|
@@ -0,0 +1,188 @@
|
|
1
|
+
package com.wix.detox.espresso.scroll
|
2
|
+
|
3
|
+
import android.graphics.Insets
|
4
|
+
import android.view.MotionEvent
|
5
|
+
import android.view.View
|
6
|
+
import android.view.WindowInsets
|
7
|
+
import androidx.test.espresso.UiController
|
8
|
+
import androidx.test.platform.app.InstrumentationRegistry
|
9
|
+
import com.wix.detox.action.common.MOTION_DIR_DOWN
|
10
|
+
import com.wix.detox.action.common.MOTION_DIR_LEFT
|
11
|
+
import com.wix.detox.action.common.MOTION_DIR_RIGHT
|
12
|
+
import com.wix.detox.action.common.MOTION_DIR_UP
|
13
|
+
import com.wix.detox.espresso.DeviceDisplay
|
14
|
+
import org.junit.Test
|
15
|
+
import org.junit.runner.RunWith
|
16
|
+
import org.mockito.kotlin.any
|
17
|
+
import org.mockito.kotlin.argumentCaptor
|
18
|
+
import org.mockito.kotlin.mock
|
19
|
+
import org.mockito.kotlin.verify
|
20
|
+
import org.mockito.kotlin.whenever
|
21
|
+
import org.robolectric.RobolectricTestRunner
|
22
|
+
import org.robolectric.annotation.Config
|
23
|
+
import kotlin.test.assertEquals
|
24
|
+
|
25
|
+
private const val INSETS_SIZE = 100
|
26
|
+
private const val SCROLL_RANGE_SAFE_PERCENT = 0.9f // ScrollHelper.SCROLL_RANGE_SAFE_PERCENT
|
27
|
+
|
28
|
+
@Config(
|
29
|
+
qualifiers = "xxxhdpi", // 1280x1880
|
30
|
+
sdk = [33]
|
31
|
+
)
|
32
|
+
@RunWith(RobolectricTestRunner::class)
|
33
|
+
class ScrollHelperTest {
|
34
|
+
|
35
|
+
private val display = DeviceDisplay.getScreenSizeInPX()
|
36
|
+
private val displayWidth = display[0].toInt()
|
37
|
+
private val displayHeight = display[1].toInt()
|
38
|
+
private val touchSlopPx = ScrollHelper.getViewConfiguration().scaledTouchSlop
|
39
|
+
private val safetyMarginPx = DeviceDisplay.convertDpiToPx(2.0)
|
40
|
+
|
41
|
+
private val uiControllerMock = mock<UiController>()
|
42
|
+
private val viewMock = mockViewWithGestureNavigation(displayWidth, displayHeight)
|
43
|
+
|
44
|
+
@Test
|
45
|
+
fun `should scrolling down by 200 when gesture navigation enabled`() {
|
46
|
+
val amountInDp = 200.0
|
47
|
+
val amountInPx = amountInDp * DeviceDisplay.getDensity()
|
48
|
+
|
49
|
+
ScrollHelper.perform(uiControllerMock, viewMock, MOTION_DIR_DOWN, amountInDp, null, null)
|
50
|
+
|
51
|
+
val upEvent = getUpEvent()
|
52
|
+
// Verify that the scroll started at the center of the view
|
53
|
+
assertEquals(displayWidth / 2.0, upEvent.x.toDouble(), 0.0)
|
54
|
+
// Verify that the scroll ended at the center of the view minus the requested amount
|
55
|
+
assertEquals(displayHeight - amountInPx - touchSlopPx - safetyMarginPx - INSETS_SIZE, upEvent.y.toDouble(), 0.0)
|
56
|
+
}
|
57
|
+
|
58
|
+
@Test
|
59
|
+
fun `should scrolling down by 200 when gesture navigation disabled`() {
|
60
|
+
val amountInDp = 200.0
|
61
|
+
val amountInPx = amountInDp * DeviceDisplay.getDensity()
|
62
|
+
|
63
|
+
val viewMock = mockViewWithoutGestureNavigation(displayWidth, displayHeight)
|
64
|
+
ScrollHelper.perform(uiControllerMock, viewMock, MOTION_DIR_DOWN, amountInDp, null, null)
|
65
|
+
|
66
|
+
val upEvent = getUpEvent()
|
67
|
+
// Verify that the scroll started at the center of the view
|
68
|
+
assertEquals(displayWidth / 2.0, upEvent.x.toDouble(), 0.0)
|
69
|
+
// Verify that the scroll ended at the center of the view minus the requested amount
|
70
|
+
assertEquals(displayHeight - amountInPx - touchSlopPx - safetyMarginPx, upEvent.y.toDouble(), 0.0)
|
71
|
+
}
|
72
|
+
|
73
|
+
@Test
|
74
|
+
fun `should scroll down to edge on full screen view when gesture navigation enabled`() {
|
75
|
+
ScrollHelper.performOnce(uiControllerMock, viewMock, MOTION_DIR_DOWN, null, null)
|
76
|
+
val upEvent = getUpEvent()
|
77
|
+
val amountInPx = displayHeight * SCROLL_RANGE_SAFE_PERCENT
|
78
|
+
|
79
|
+
// Calculate where the scroll should end
|
80
|
+
val targetY = displayHeight - amountInPx -
|
81
|
+
touchSlopPx -
|
82
|
+
safetyMarginPx -
|
83
|
+
INSETS_SIZE
|
84
|
+
|
85
|
+
assertEquals(displayWidth / 2.0, upEvent.x.toDouble(), 0.0)
|
86
|
+
assertEquals(targetY, upEvent.y, 0.0f)
|
87
|
+
}
|
88
|
+
|
89
|
+
@Test
|
90
|
+
fun `should scroll left to edge on full screen view when gesture navigation enabled`() {
|
91
|
+
ScrollHelper.performOnce(uiControllerMock, viewMock, MOTION_DIR_LEFT, null, null)
|
92
|
+
val upEvent = getUpEvent()
|
93
|
+
val amountInPx = displayWidth * SCROLL_RANGE_SAFE_PERCENT
|
94
|
+
|
95
|
+
// Calculate where the scroll should end
|
96
|
+
val targetX = amountInPx +
|
97
|
+
touchSlopPx +
|
98
|
+
INSETS_SIZE
|
99
|
+
|
100
|
+
assertEquals(targetX, upEvent.x, 0.0f)
|
101
|
+
assertEquals(displayHeight / 2.0, upEvent.y.toDouble(), 0.0)
|
102
|
+
}
|
103
|
+
|
104
|
+
@Test
|
105
|
+
fun `should scroll up to edge on full screen view when gesture navigation enabled`() {
|
106
|
+
ScrollHelper.performOnce(uiControllerMock, viewMock, MOTION_DIR_UP,null, null)
|
107
|
+
val upEvent = getUpEvent()
|
108
|
+
val amountInPx = displayHeight * SCROLL_RANGE_SAFE_PERCENT
|
109
|
+
|
110
|
+
// Calculate where the scroll should end
|
111
|
+
val targetY = amountInPx +
|
112
|
+
touchSlopPx +
|
113
|
+
INSETS_SIZE
|
114
|
+
|
115
|
+
assertEquals(displayWidth / 2.0, upEvent.x.toDouble(), 0.0)
|
116
|
+
assertEquals(targetY, upEvent.y, 0.0f)
|
117
|
+
}
|
118
|
+
|
119
|
+
@Test
|
120
|
+
fun `should scroll right to edge on full screen view when gesture navigation enabled`() {
|
121
|
+
ScrollHelper.performOnce(uiControllerMock, viewMock, MOTION_DIR_RIGHT, null, null)
|
122
|
+
val upEvent = getUpEvent()
|
123
|
+
val amountInPx = displayWidth * SCROLL_RANGE_SAFE_PERCENT
|
124
|
+
|
125
|
+
// Calculate where the scroll should end
|
126
|
+
val targetX = displayWidth - amountInPx -
|
127
|
+
touchSlopPx -
|
128
|
+
safetyMarginPx -
|
129
|
+
INSETS_SIZE
|
130
|
+
|
131
|
+
assertEquals(targetX, upEvent.x, 0.0f)
|
132
|
+
assertEquals(displayHeight / 2.0, upEvent.y.toDouble(), 0.0)
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Get the performed UP event from the ui controller
|
137
|
+
*/
|
138
|
+
private fun getUpEvent(): MotionEvent {
|
139
|
+
val capture = argumentCaptor<Iterable<MotionEvent>>()
|
140
|
+
// Capture the events from the ui controller
|
141
|
+
verify(uiControllerMock).injectMotionEventSequence(capture.capture())
|
142
|
+
|
143
|
+
val listOfCapturedEvents = capture.firstValue.toList()
|
144
|
+
// The last event is the UP event with the target coordinates. All of the rest are not interesting
|
145
|
+
return listOfCapturedEvents.last()
|
146
|
+
}
|
147
|
+
|
148
|
+
private fun mockViewWithoutGestureNavigation(displayWidth: Int, displayHeight: Int): View {
|
149
|
+
// This is how we disable gesture navigation
|
150
|
+
val windowInsets = mock<WindowInsets>() {
|
151
|
+
whenever(it.systemGestureInsets).thenReturn(
|
152
|
+
Insets.of(0, 0, 0, 0)
|
153
|
+
)
|
154
|
+
}
|
155
|
+
|
156
|
+
return mockView(displayWidth, displayHeight, windowInsets)
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* Mock a view with gesture navigation enabled
|
161
|
+
*/
|
162
|
+
private fun mockViewWithGestureNavigation(displayWidth: Int, displayHeight: Int): View {
|
163
|
+
// This is how we enable gesture navigation
|
164
|
+
val windowInsets = mock<WindowInsets>() {
|
165
|
+
whenever(it.systemGestureInsets).thenReturn(
|
166
|
+
Insets.of(INSETS_SIZE, INSETS_SIZE, INSETS_SIZE, INSETS_SIZE)
|
167
|
+
)
|
168
|
+
}
|
169
|
+
|
170
|
+
return mockView(displayWidth, displayHeight, windowInsets)
|
171
|
+
}
|
172
|
+
|
173
|
+
private fun mockView(
|
174
|
+
displayWidth: Int,
|
175
|
+
displayHeight: Int,
|
176
|
+
windowInsets: WindowInsets
|
177
|
+
): View {
|
178
|
+
val view = mock<View>() {
|
179
|
+
whenever(it.width).thenReturn(displayWidth)
|
180
|
+
whenever(it.height).thenReturn(displayHeight)
|
181
|
+
whenever(it.canScrollVertically(any())).thenReturn(true) // We allow endless scroll
|
182
|
+
whenever(it.canScrollHorizontally(any())).thenReturn(true) // We allow endless scroll
|
183
|
+
whenever(it.context).thenReturn(InstrumentationRegistry.getInstrumentation().targetContext)
|
184
|
+
whenever(it.rootWindowInsets).thenReturn(windowInsets)
|
185
|
+
}
|
186
|
+
return view
|
187
|
+
}
|
188
|
+
}
|
package/detox.d.ts
CHANGED
@@ -1363,10 +1363,13 @@ declare global {
|
|
1363
1363
|
|
1364
1364
|
/**
|
1365
1365
|
* Scroll to edge.
|
1366
|
-
* @
|
1366
|
+
* @param edge - left|right|top|bottom
|
1367
|
+
* @param startPositionX - the X starting scroll position, in percentage; valid input: `[0.0, 1.0]`, `NaN`; default: `NaN`—choose the best value automatically
|
1368
|
+
* @param startPositionY - the Y starting scroll position, in percentage; valid input: `[0.0, 1.0]`, `NaN`; default: `NaN`—choose the best value automatically
|
1369
|
+
* @example await element(by.id('scrollView')).scrollTo('bottom', NaN, 0.85);
|
1367
1370
|
* @example await element(by.id('scrollView')).scrollTo('top');
|
1368
1371
|
*/
|
1369
|
-
scrollTo(edge: Direction): Promise<void>;
|
1372
|
+
scrollTo(edge: Direction, startPositionX?: number, startPositionY?: number): Promise<void>;
|
1370
1373
|
|
1371
1374
|
/**
|
1372
1375
|
* Adjust slider to position.
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "detox",
|
3
3
|
"description": "E2E tests and automation for mobile",
|
4
|
-
"version": "20.
|
4
|
+
"version": "20.15.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -109,5 +109,5 @@
|
|
109
109
|
"browserslist": [
|
110
110
|
"node 14"
|
111
111
|
],
|
112
|
-
"gitHead": "
|
112
|
+
"gitHead": "bed7b965b2180bd3c628e242b9f78a80660c371f"
|
113
113
|
}
|
@@ -81,10 +81,10 @@ class ScrollAmountStopAtEdgeAction extends Action {
|
|
81
81
|
}
|
82
82
|
|
83
83
|
class ScrollEdgeAction extends Action {
|
84
|
-
constructor(edge) {
|
84
|
+
constructor(edge, startPositionX = -1, startPositionY = -1) {
|
85
85
|
super();
|
86
86
|
|
87
|
-
this._call = invoke.callDirectly(DetoxActionApi.scrollToEdge(edge));
|
87
|
+
this._call = invoke.callDirectly(DetoxActionApi.scrollToEdge(edge, startPositionX, startPositionY));
|
88
88
|
}
|
89
89
|
}
|
90
90
|
|
@@ -93,12 +93,12 @@ class NativeElement {
|
|
93
93
|
return await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
94
94
|
}
|
95
95
|
|
96
|
-
async scrollTo(edge) {
|
96
|
+
async scrollTo(edge, startPositionX, startPositionY) {
|
97
97
|
// override the user's element selection with an extended matcher that looks for UIScrollView children
|
98
98
|
this._matcher = this._matcher._extendToDescendantScrollViews();
|
99
99
|
|
100
|
-
const action = new actions.ScrollEdgeAction(edge);
|
101
|
-
const traceDescription = actionDescription.scrollTo(edge);
|
100
|
+
const action = new actions.ScrollEdgeAction(edge, startPositionX, startPositionY);
|
101
|
+
const traceDescription = actionDescription.scrollTo(edge, startPositionX, startPositionY);
|
102
102
|
return await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
103
103
|
}
|
104
104
|
|
@@ -140,7 +140,6 @@ class NativeElement {
|
|
140
140
|
}
|
141
141
|
|
142
142
|
async takeScreenshot(screenshotName) {
|
143
|
-
// TODO this should be moved to a lower-layer handler of this use-case
|
144
143
|
const action = new actions.TakeElementScreenshot();
|
145
144
|
const traceDescription = actionDescription.takeScreenshot(screenshotName);
|
146
145
|
const resultBase64 = await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
@@ -68,8 +68,10 @@ class DetoxAction {
|
|
68
68
|
};
|
69
69
|
}
|
70
70
|
|
71
|
-
static scrollToEdge(edge) {
|
71
|
+
static scrollToEdge(edge, startOffsetPercentX, startOffsetPercentY) {
|
72
72
|
if (typeof edge !== "string") throw new Error("edge should be a string, but got " + (edge + (" (" + (typeof edge + ")"))));
|
73
|
+
if (typeof startOffsetPercentX !== "number") throw new Error("startOffsetPercentX should be a number, but got " + (startOffsetPercentX + (" (" + (typeof startOffsetPercentX + ")"))));
|
74
|
+
if (typeof startOffsetPercentY !== "number") throw new Error("startOffsetPercentY should be a number, but got " + (startOffsetPercentY + (" (" + (typeof startOffsetPercentY + ")"))));
|
73
75
|
return {
|
74
76
|
target: {
|
75
77
|
type: "Class",
|
@@ -79,6 +81,12 @@ class DetoxAction {
|
|
79
81
|
args: [{
|
80
82
|
type: "Integer",
|
81
83
|
value: sanitize_android_edge(edge)
|
84
|
+
}, {
|
85
|
+
type: "Double",
|
86
|
+
value: startOffsetPercentX
|
87
|
+
}, {
|
88
|
+
type: "Double",
|
89
|
+
value: startOffsetPercentY
|
82
90
|
}]
|
83
91
|
};
|
84
92
|
}
|
@@ -28,7 +28,7 @@ class ActionInteraction extends Interaction {
|
|
28
28
|
constructor(invocationManager, matcher, action, traceDescription) {
|
29
29
|
super(invocationManager, traceDescription);
|
30
30
|
this._call = EspressoDetoxApi.perform(matcher, action._call);
|
31
|
-
// TODO: move this.execute() here from the caller
|
31
|
+
// TODO [2024-12-01]: move this.execute() here from the caller
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
@@ -39,7 +39,7 @@ class MatcherAssertionInteraction extends Interaction {
|
|
39
39
|
|
40
40
|
matcher = notCondition ? matcher.not : matcher;
|
41
41
|
this._call = DetoxAssertionApi.assertMatcher(call(element._call), matcher._call.value);
|
42
|
-
// TODO: move this.execute() here from the caller
|
42
|
+
// TODO [2024-12-01]: move this.execute() here from the caller
|
43
43
|
}
|
44
44
|
}
|
45
45
|
|
@@ -76,7 +76,7 @@ class ToggleMatcher extends NativeMatcher {
|
|
76
76
|
}
|
77
77
|
}
|
78
78
|
|
79
|
-
//
|
79
|
+
// NOTE: Please be aware, that this is just a dummy matcher
|
80
80
|
class TraitsMatcher extends NativeMatcher {
|
81
81
|
constructor(value) {
|
82
82
|
super();
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ArtifactPluginsProvider {
|
2
|
-
declareArtifactPlugins({ client }) {} // eslint-disable-line no-unused-vars
|
2
|
+
declareArtifactPlugins({ client }) {} // eslint-disable-line no-unused-vars,@typescript-eslint/no-unused-vars
|
3
3
|
}
|
4
4
|
|
5
5
|
class AndroidArtifactPluginsProvider extends ArtifactPluginsProvider {
|
@@ -1,7 +1,6 @@
|
|
1
1
|
const path = require('path');
|
2
2
|
|
3
3
|
const fs = require('../../utils/fsext');
|
4
|
-
const log = require('../../utils/logger').child({ cat: 'artifacts-plugin,artifacts' });
|
5
4
|
const FileArtifact = require('../templates/artifact/FileArtifact');
|
6
5
|
const temporaryPath = require('../utils/temporaryPath');
|
7
6
|
|
@@ -134,7 +134,7 @@ class AsyncWebSocket {
|
|
134
134
|
}
|
135
135
|
}
|
136
136
|
|
137
|
-
// TODO: handle this leaked abstraction some day
|
137
|
+
// TODO [2024-12-01]: handle this leaked abstraction some day
|
138
138
|
hasPendingActions() {
|
139
139
|
return _.some(this.inFlightPromises, p => p.message.type !== 'currentStatus');
|
140
140
|
}
|
@@ -168,7 +168,7 @@ class AsyncWebSocket {
|
|
168
168
|
case WebSocket.CONNECTING: return 'opening';
|
169
169
|
case WebSocket.OPEN: return 'open';
|
170
170
|
/* istanbul ignore next */
|
171
|
-
default:
|
171
|
+
default:
|
172
172
|
return undefined;
|
173
173
|
}
|
174
174
|
}
|
package/src/client/Client.js
CHANGED
@@ -187,14 +187,14 @@ class Client {
|
|
187
187
|
this._whenAppIsReady = new Deferred();
|
188
188
|
|
189
189
|
await this._whenAppIsConnected.promise;
|
190
|
-
// TODO: optimize traffic (!) - we can just listen for 'ready' event
|
190
|
+
// TODO [2024-12-01]: optimize traffic (!) - we can just listen for 'ready' event
|
191
191
|
// if app always sends it upon load completion. On iOS it works,
|
192
192
|
// but not on Android. Afterwards, this will suffice:
|
193
193
|
//
|
194
194
|
// await this._whenAppIsReady.promise;
|
195
195
|
}
|
196
196
|
|
197
|
-
// TODO: move to else branch after the optimization
|
197
|
+
// TODO [2024-12-01]: move to else branch after the optimization ↑↑
|
198
198
|
if (!this._whenAppIsReady.isResolved()) {
|
199
199
|
this._whenAppIsReady = new Deferred();
|
200
200
|
await this.sendAction(new actions.Ready());
|
@@ -7,7 +7,7 @@ class EmulatorVersionResolver {
|
|
7
7
|
this.version = undefined;
|
8
8
|
}
|
9
9
|
|
10
|
-
async resolve(isHeadless = false) {
|
10
|
+
async resolve(isHeadless = false) {
|
11
11
|
if (!this.version) {
|
12
12
|
this.version = await this._resolve(isHeadless);
|
13
13
|
}
|
@@ -39,7 +39,6 @@ class SimulatorAllocDriver {
|
|
39
39
|
async allocate(deviceConfig) {
|
40
40
|
const deviceQuery = new SimulatorQuery(deviceConfig.device);
|
41
41
|
|
42
|
-
// TODO Delegate this onto a well tested allocator class
|
43
42
|
const udid = await this._deviceRegistry.registerDevice(async () => {
|
44
43
|
return await this._findOrCreateDevice(deviceQuery);
|
45
44
|
});
|
@@ -42,7 +42,7 @@ class AndroidEmulator extends DeviceAllocatorFactory {
|
|
42
42
|
}
|
43
43
|
|
44
44
|
class AndroidAttached extends DeviceAllocatorFactory {
|
45
|
-
_createDriver({ detoxSession
|
45
|
+
_createDriver({ detoxSession }) {
|
46
46
|
const serviceLocator = require('../../servicelocator/android');
|
47
47
|
const adb = serviceLocator.adb;
|
48
48
|
const DeviceRegistry = require('../../allocation/DeviceRegistry');
|
@@ -2,7 +2,7 @@
|
|
2
2
|
const DeviceAllocatorFactory = require('./base');
|
3
3
|
|
4
4
|
class IosSimulator extends DeviceAllocatorFactory {
|
5
|
-
_createDriver({ detoxConfig, detoxSession
|
5
|
+
_createDriver({ detoxConfig, detoxSession }) {
|
6
6
|
const AppleSimUtils = require('../../../devices/common/drivers/ios/tools/AppleSimUtils');
|
7
7
|
const applesimutils = new AppleSimUtils();
|
8
8
|
|
@@ -8,7 +8,7 @@ const { escape } = require('../../../../../utils/pipeCommands');
|
|
8
8
|
const DeviceHandle = require('../tools/DeviceHandle');
|
9
9
|
const EmulatorHandle = require('../tools/EmulatorHandle');
|
10
10
|
|
11
|
-
const INSTALL_TIMEOUT = 45000;
|
11
|
+
const INSTALL_TIMEOUT = 45000;
|
12
12
|
|
13
13
|
class ADB {
|
14
14
|
constructor() {
|
@@ -345,7 +345,6 @@ class ADB {
|
|
345
345
|
return this.adbCmd(deviceId, `emu kill`);
|
346
346
|
}
|
347
347
|
|
348
|
-
// TODO refactor the whole thing so as to make usage of BinaryExec -- similar to EmulatorExec
|
349
348
|
async adbCmd(deviceId, params, options = {}) {
|
350
349
|
const serial = `${deviceId ? `-s ${deviceId}` : ''}`;
|
351
350
|
const cmd = `"${this.adbBin}" ${serial} ${params}`;
|
@@ -2,8 +2,6 @@ const RuntimeDeviceFactory = require('./base');
|
|
2
2
|
|
3
3
|
class RuntimeDriverFactoryIos extends RuntimeDeviceFactory {
|
4
4
|
_createDriverDependencies(commonDeps) {
|
5
|
-
const { eventEmitter } = commonDeps;
|
6
|
-
|
7
5
|
const AppleSimUtils = require('../../../devices/common/drivers/ios/tools/AppleSimUtils');
|
8
6
|
const applesimutils = new AppleSimUtils();
|
9
7
|
|
package/src/ios/expectTwo.js
CHANGED
@@ -247,10 +247,13 @@ class Element {
|
|
247
247
|
return this.withAction('scroll', traceDescription, pixels, direction, startPositionX, startPositionY);
|
248
248
|
}
|
249
249
|
|
250
|
-
scrollTo(edge) {
|
250
|
+
scrollTo(edge, startPositionX = NaN, startPositionY = NaN) {
|
251
251
|
if (!['left', 'right', 'top', 'bottom'].some(option => option === edge)) throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge);
|
252
|
-
|
253
|
-
|
252
|
+
if (typeof startPositionX !== 'number') throw new Error('startPositionX should be a number, but got ' + (startPositionX + (' (' + (typeof startPositionX + ')'))));
|
253
|
+
if (typeof startPositionY !== 'number') throw new Error('startPositionY should be a number, but got ' + (startPositionY + (' (' + (typeof startPositionY + ')'))));
|
254
|
+
|
255
|
+
const traceDescription = actionDescription.scrollTo(edge, startPositionX, startPositionY);
|
256
|
+
return this.withAction('scrollTo', traceDescription, edge, startPositionX, startPositionY);
|
254
257
|
}
|
255
258
|
|
256
259
|
swipe(direction, speed = 'fast', normalizedSwipeOffset = NaN, normalizedStartingPointX = NaN, normalizedStartingPointY = NaN) {
|
package/src/ipc/IPCServer.js
CHANGED
@@ -40,7 +40,7 @@ class IPCServer {
|
|
40
40
|
this._ipc.config.logger = (msg) => this._logger.trace(msg);
|
41
41
|
|
42
42
|
await new Promise((resolve) => {
|
43
|
-
//
|
43
|
+
// It is worth to handle rejection here some day
|
44
44
|
this._ipc.serve(() => resolve());
|
45
45
|
this._ipc.server.on('conductEarlyTeardown', this.onConductEarlyTeardown.bind(this));
|
46
46
|
this._ipc.server.on('registerContext', this.onRegisterContext.bind(this));
|
@@ -98,7 +98,6 @@ class DetoxPrimaryContext extends DetoxContext {
|
|
98
98
|
data: this[$sessionState],
|
99
99
|
}, getCurrentCommand());
|
100
100
|
|
101
|
-
// TODO: IPC Server creation ought to be delegated to a generator/factory.
|
102
101
|
const IPCServer = require('../ipc/IPCServer');
|
103
102
|
this[_ipcServer] = new IPCServer({
|
104
103
|
sessionState: this[$sessionState],
|
@@ -111,7 +110,6 @@ class DetoxPrimaryContext extends DetoxContext {
|
|
111
110
|
|
112
111
|
await this[_ipcServer].init();
|
113
112
|
|
114
|
-
// TODO: Detox-server creation ought to be delegated to a generator/factory.
|
115
113
|
const DetoxServer = require('../server/DetoxServer');
|
116
114
|
if (sessionConfig.autoStart) {
|
117
115
|
this[_wss] = new DetoxServer({
|
@@ -124,7 +122,6 @@ class DetoxPrimaryContext extends DetoxContext {
|
|
124
122
|
await this[_wss].open();
|
125
123
|
}
|
126
124
|
|
127
|
-
// TODO: double check that this config is indeed propogated onto the client create at the detox-worker side
|
128
125
|
if (!sessionConfig.server && this[_wss]) {
|
129
126
|
// @ts-ignore
|
130
127
|
sessionConfig.server = `ws://localhost:${this[_wss].port}`;
|
@@ -12,8 +12,9 @@ module.exports = {
|
|
12
12
|
pinchWithAngle: (direction, speed, angle) => `pinch with direction ${direction}, speed ${speed}, and angle ${angle}`,
|
13
13
|
replaceText: (value) => `replace input text: "${value}"`,
|
14
14
|
scroll: (amount, direction, startPositionX, startPositionY) =>
|
15
|
-
`scroll ${amount} pixels ${direction}${startPositionX !== undefined
|
16
|
-
scrollTo: (edge) =>
|
15
|
+
`scroll ${amount} pixels ${direction}${startPositionX !== undefined || startPositionY !== undefined ? ` from normalized position (${startPositionX}, ${startPositionY})` : ''}`,
|
16
|
+
scrollTo: (edge, startPositionX, startPositionY) =>
|
17
|
+
`scroll to ${edge} ${startPositionX !== undefined || startPositionY !== undefined ? ` from normalized position (${startPositionX}, ${startPositionY})` : ''}`,
|
17
18
|
scrollToIndex: (index) => `scroll to index #${index}`,
|
18
19
|
setColumnToValue: (column, value) => `set column ${column} to value ${value}`,
|
19
20
|
setDatePickerDate: (dateString, dateFormat) => `set date picker date to ${dateString} using format ${dateFormat}`,
|
@@ -1 +0,0 @@
|
|
1
|
-
eaf5c6ab60c7263a63ded415775ca4bb
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha1
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
d9e21af9ba2d52a1de261f6d67ce0164ad6abe74
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha256
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
691dfc26633bf96a4b4e85192596bcdc55dce2422dc5be9ea411e72d4b4d21ac
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-javadoc.jar.sha512
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
8bada7530f9c27c654d88e42c4d516dc3171096db17fb72e74a3495ee65ed47ab6657b3ad20047d45c8a735cc8fe094fdb2c381a9e28f60eca9da1d6b4ca3f91
|
@@ -1 +0,0 @@
|
|
1
|
-
3eafa3c68aa4052456fdb2949577c4b9
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha1
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
cda1ec11d74883ff6b9200812a9274c0dd6ad9c6
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha256
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
f8b7caf61b6e1ffc3233b570be4d12b76b334d15bfce9b7dd102fe4ed2567af6
|
package/Detox-android/com/wix/detox/20.14.10-smoke.1/detox-20.14.10-smoke.1-sources.jar.sha512
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
9df51128bb51f571479522a86589c5aee21f8cc4b1cc652fcfc17712e406632b83e65a5c59e2229fd3ec3709e8c0c9baef0b44ed3aabdfaa85dd3cc848104780
|
Binary file
|
@@ -1 +0,0 @@
|
|
1
|
-
c27920150917efb5b25878186e904fe0
|
@@ -1 +0,0 @@
|
|
1
|
-
ad9e12738ca3c82606a58bacea6d50b51687aee9
|
@@ -1 +0,0 @@
|
|
1
|
-
ab07c0011f9cee612e5b56ea42618978b75a5cfff9841766fc3f796e730c3571
|
@@ -1 +0,0 @@
|
|
1
|
-
a26f964a1ef775262740a23fbbeca9e5754a5da7896bcab22a476f684d40168b67ad4a97087a1f6fe484343e70eb32063adfeac3a2879f887e8d7fc616e6eacc
|
@@ -1 +0,0 @@
|
|
1
|
-
cff533719289526fac23e59c4e616616
|
@@ -1 +0,0 @@
|
|
1
|
-
d017c7b801f2b09f6790aa2a401f8eaaac49b383
|
@@ -1 +0,0 @@
|
|
1
|
-
e1ccabafa0a01ced62ce084048746fef6be5355f716c1213f7d7794089afb958
|
@@ -1 +0,0 @@
|
|
1
|
-
f4c3c6a0d61bde3d6613ad3c01b759b39ca96b6746f6df703dc5c4cc958870ffe3d8154c98dca9cb0a639025ec4c0d5f6af6c134498f846ed4847f57ec9c1714
|