From 32e539ae170d8965fee0d8fc1b9ee2a2259255e0 Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Tue, 22 Jun 2021 14:33:16 +0300 Subject: [PATCH 1/9] Improve scroll speed and expose scrollToIndex --- .../com/wix/detox/espresso/DetoxAction.java | 19 ++- .../detox/espresso/action/ScrollToIndex.kt | 126 ++++++++++++++++++ .../detox/espresso/scroll/FlinglessSwiper.kt | 4 +- detox/index.d.ts | 4 + detox/src/android/actions/native.js | 16 +++ detox/src/android/core/NativeElement.js | 5 + detox/src/android/espressoapi/DetoxAction.js | 15 +++ detox/test/e2e/03.actions-scroll.test.js | 34 +++++ docs/APIRef.ActionsOnElement.md | 12 +- 9 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt diff --git a/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java b/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java index 2cced13260..cf6d93381e 100644 --- a/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +++ b/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java @@ -7,6 +7,7 @@ import com.wix.detox.espresso.action.DetoxMultiTap; import com.wix.detox.espresso.action.RNClickAction; import com.wix.detox.espresso.action.ScreenshotResult; +import com.wix.detox.espresso.action.ScrollToIndex; import com.wix.detox.espresso.action.TakeViewScreenshotAction; import com.wix.detox.espresso.action.GetAttributesAction; import com.wix.detox.action.common.MotionDir; @@ -97,8 +98,8 @@ public void perform(UiController uiController, View view) { /** * Scrolls the View in a direction by the Density Independent Pixel amount. * - * @param direction Direction to scroll (see {@link MotionDir}) - * @param amountInDP Density Independent Pixels + * @param direction Direction to scroll (see {@link MotionDir}) + * @param amountInDP Density Independent Pixels * @param startOffsetPercentX Percentage denoting where X-swipe should start, with respect to the scrollable view. * @param startOffsetPercentY Percentage denoting where Y-swipe should start, with respect to the scrollable view. */ @@ -114,8 +115,8 @@ public static ViewAction scrollInDirection(final int direction, final double amo * where the scrolling-edge is reached, by throwing the {@link StaleActionException} exception (i.e. * so as to make this use case manageable by the user). * - * @param direction Direction to scroll (see {@link MotionDir}) - * @param amountInDP Density Independent Pixels + * @param direction Direction to scroll (see {@link MotionDir}) + * @param amountInDP Density Independent Pixels * @param startOffsetPercentX Percentage denoting where X-swipe should start, with respect to the scrollable view. * @param startOffsetPercentY Percentage denoting where Y-swipe should start, with respect to the scrollable view. */ @@ -128,9 +129,9 @@ public static ViewAction scrollInDirectionStaleAtEdge(final int direction, final /** * Swipes the View in a direction. * - * @param direction Direction to swipe (see {@link MotionDir}) - * @param fast true if fast, false if slow - * @param normalizedOffset or "swipe amount" between 0.0 and 1.0, relative to the screen width/height + * @param direction Direction to swipe (see {@link MotionDir}) + * @param fast true if fast, false if slow + * @param normalizedOffset or "swipe amount" between 0.0 and 1.0, relative to the screen width/height * @param normalizedStartingPointX X coordinate of swipe starting point (between 0.0 and 1.0), relative to the view width * @param normalizedStartingPointY Y coordinate of swipe starting point (between 0.0 and 1.0), relative to the view height */ @@ -143,6 +144,10 @@ public static ViewAction getAttributes() { return new GetAttributesAction(); } + public static ViewAction scrollToIndex(int index) { + return new ScrollToIndex(index); + } + public static ViewAction takeViewScreenshot() { return new ViewActionWithResult() { private final TakeViewScreenshotAction action = new TakeViewScreenshotAction(); diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt new file mode 100644 index 0000000000..b5b45f380c --- /dev/null +++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt @@ -0,0 +1,126 @@ +package com.wix.detox.espresso.action + +import android.view.View +import android.view.ViewGroup +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.matcher.ViewMatchers +import com.facebook.react.views.scroll.ReactHorizontalScrollView +import com.facebook.react.views.scroll.ReactScrollView +import com.wix.detox.action.common.MOTION_DIR_DOWN +import com.wix.detox.action.common.MOTION_DIR_LEFT +import com.wix.detox.action.common.MOTION_DIR_RIGHT +import com.wix.detox.action.common.MOTION_DIR_UP +import com.wix.detox.espresso.scroll.ScrollEdgeException +import com.wix.detox.espresso.scroll.ScrollHelper +import org.hamcrest.Matcher +import org.hamcrest.Matchers + +class ScrollToIndex(private val index: Int) : ViewAction { + override fun getConstraints(): Matcher { + return Matchers.anyOf( + Matchers.allOf( + ViewMatchers.isAssignableFrom( + View::class.java + ), Matchers.instanceOf( + ReactScrollView::class.java + ) + ), + Matchers.allOf( + ViewMatchers.isAssignableFrom( + View::class.java + ), Matchers.instanceOf(ReactHorizontalScrollView::class.java) + ) + ) + } + + override fun getDescription(): String { + return "scrollToIndex" + } + + override fun perform(uiController: UiController?, view: View?) { + if (index < 0) return + + val offsetPercent = 0.4f + val reactScrollView = view as ViewGroup + val internalContainer = reactScrollView.getChildAt(0) as ViewGroup + val childCount = internalContainer.childCount + if (index >= childCount) return + + val isHorizontalScrollView = getIsHorizontalScrollView(reactScrollView) + val targetPosition = getTargetPosition(isHorizontalScrollView, internalContainer, index) + var currentPosition = getCurrentPosition(isHorizontalScrollView, reactScrollView) + val jumpSize = getTargetDimension(isHorizontalScrollView, internalContainer, index) + val scrollDirection = + getScrollDirection(isHorizontalScrollView, currentPosition, targetPosition) + + // either we'll find the target view or we'll hit the edge of the scrollview + + // either we'll find the target view or we'll hit the edge of the scrollview + while (true) { + if (Math.abs(currentPosition - targetPosition) < jumpSize) { + // we found the target view + return + } + currentPosition = try { + ScrollHelper.perform( + uiController, + view, + scrollDirection, + jumpSize.toDouble(), + offsetPercent, + offsetPercent + ) + getCurrentPosition(isHorizontalScrollView, reactScrollView) + } catch (e: ScrollEdgeException) { + // we hit the edge + return + } + } + } + +} + +private fun getScrollDirection( + isHorizontalScrollView: Boolean, + currentPosition: Int, + targetPosition: Int +): Int { + return if (isHorizontalScrollView) { + if (currentPosition < targetPosition) MOTION_DIR_RIGHT else MOTION_DIR_LEFT + } else { + if (currentPosition < targetPosition) MOTION_DIR_DOWN else MOTION_DIR_UP + } +} + +private fun getIsHorizontalScrollView(scrollView: ViewGroup): Boolean { + return scrollView.canScrollHorizontally(1) || scrollView.canScrollHorizontally(-1) +} + +private fun getCurrentPosition(isHorizontalScrollView: Boolean, scrollView: ViewGroup): Int { + return if (isHorizontalScrollView) scrollView.scrollX else scrollView.scrollY +} + +private fun getTargetDimension( + isHorizontalScrollView: Boolean, + internalContainer: ViewGroup, + index: Int +): Int { + return if (isHorizontalScrollView) internalContainer.getChildAt(index).measuredWidth else internalContainer.getChildAt( + index + ).measuredHeight +} + +private fun getTargetPosition( + isHorizontalScrollView: Boolean, + internalContainer: ViewGroup, + index: Int +): Int { + var necessaryTarget = 0 + for (childIndex in 0 until index) { + necessaryTarget += if (isHorizontalScrollView) internalContainer.getChildAt(childIndex).measuredWidth else internalContainer.getChildAt( + childIndex + ).measuredHeight + } + return necessaryTarget +} \ No newline at end of file diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt index 3a7f271f2d..b69ecc3ac9 100644 --- a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt +++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt @@ -92,7 +92,7 @@ class FlinglessSwiper @JvmOverloads constructor( companion object { // private const val LOG_TAG = "DetoxBatchedSwiper" - private const val VELOCITY_SAFETY_RATIO = .85f - private const val FAST_EVENTS_RATIO = .75f + private const val VELOCITY_SAFETY_RATIO = .99f + private const val FAST_EVENTS_RATIO = .99f } } diff --git a/detox/index.d.ts b/detox/index.d.ts index caf66cf2a5..6380f2342c 100644 --- a/detox/index.d.ts +++ b/detox/index.d.ts @@ -1032,6 +1032,10 @@ declare global { startPositionY?: number, ): Promise; + scrollToIndex( + index: Number + ): Promise; + /** * Scroll to edge. * @example await element(by.id('scrollView')).scrollTo('bottom'); diff --git a/detox/src/android/actions/native.js b/detox/src/android/actions/native.js index cc9ba88774..e4fabb85a2 100644 --- a/detox/src/android/actions/native.js +++ b/detox/src/android/actions/native.js @@ -88,6 +88,14 @@ class ScrollEdgeAction extends Action { } } +class ScrollToIndexAction extends Action { + constructor(index) { + super(); + + this._call = invoke.callDirectly(DetoxActionApi.scrollToIndex(index)); + } +} + class SwipeAction extends Action { constructor(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY) { super(); @@ -117,6 +125,13 @@ class GetAttributes extends Action { } } +class ScrollToIndex extends Action { + constructor(index) { + super(); + this._call = invoke.callDirectly(DetoxActionApi.scrollToIndex(index)); + } +} + class TakeElementScreenshot extends Action { constructor() { super(); @@ -140,4 +155,5 @@ module.exports = { ScrollEdgeAction, SwipeAction, TakeElementScreenshot, + ScrollToIndex, }; diff --git a/detox/src/android/core/NativeElement.js b/detox/src/android/core/NativeElement.js index 5c5da7fea1..b8cae37c26 100644 --- a/detox/src/android/core/NativeElement.js +++ b/detox/src/android/core/NativeElement.js @@ -79,6 +79,11 @@ class NativeElement { return await new ActionInteraction(this._invocationManager, this, new actions.ScrollEdgeAction(edge)).execute(); } + async scrollToIndex(index) { + this._selectElementWithMatcher(this._originalMatcher._extendToDescendantScrollViews()); + return await new ActionInteraction(this._invocationManager, this, new actions.ScrollToIndex(index)).execute(); + } + /** * @param {'up' | 'right' | 'down' | 'left'} direction * @param {'slow' | 'fast'} [speed] diff --git a/detox/src/android/espressoapi/DetoxAction.js b/detox/src/android/espressoapi/DetoxAction.js index 0992e62d56..104f7549cb 100644 --- a/detox/src/android/espressoapi/DetoxAction.js +++ b/detox/src/android/espressoapi/DetoxAction.js @@ -179,6 +179,21 @@ class DetoxAction { }; } + static scrollToIndex(index) { + if (typeof index !== "number") throw new Error("index should be a number, but got " + (index + (" (" + (typeof index + ")")))); + return { + target: { + type: "Class", + value: "com.wix.detox.espresso.DetoxAction" + }, + method: "scrollToIndex", + args: [{ + type: "Integer", + value: index + }] + }; + } + static takeViewScreenshot() { return { target: { diff --git a/detox/test/e2e/03.actions-scroll.test.js b/detox/test/e2e/03.actions-scroll.test.js index 0a2e76b700..09e5e74b8b 100644 --- a/detox/test/e2e/03.actions-scroll.test.js +++ b/detox/test/e2e/03.actions-scroll.test.js @@ -71,4 +71,38 @@ describe('Actions - Scroll', () => { await element(by.id('toggleScrollOverlays')).tap(); await expect(element(by.text('HText6'))).not.toBeVisible(); }); + + it('should be able to scrollToIndex on horizontal scrollviews', async () => { + // should ignore out of bounds children + await element(by.id('ScrollViewH')).scrollToIndex(3000); + await element(by.id('ScrollViewH')).scrollToIndex(-1); + await expect(element(by.text('HText1'))).toBeVisible(); + + await expect(element(by.text('HText8'))).not.toBeVisible(); + await element(by.id('ScrollViewH')).scrollToIndex(7); + await expect(element(by.text('HText8'))).toBeVisible(); + await expect(element(by.text('HText1'))).not.toBeVisible(); + + await element(by.id('ScrollViewH')).scrollToIndex(0); + await expect(element(by.text('HText1'))).toBeVisible(); + await expect(element(by.text('HText8'))).not.toBeVisible(); + }); + + it('should be able to scrollToIndex on vertical scrollviews', async () => { + // should ignore out of bounds children + await element(by.id('ScrollView161')).scrollToIndex(3000); + await element(by.id('ScrollView161')).scrollToIndex(-1); + await expect(element(by.text('Text1'))).toBeVisible(); + + await element(by.id('ScrollView161')).scrollToIndex(11); + await expect(element(by.text('Text12'))).toBeVisible(); + await expect(element(by.text('Text1'))).not.toBeVisible(); + + await element(by.id('ScrollView161')).scrollToIndex(0); + await expect(element(by.text('Text1'))).toBeVisible(); + await expect(element(by.text('Text12'))).not.toBeVisible(); + + await element(by.id('ScrollView161')).scrollToIndex(7); + await expect(element(by.text('Text8'))).toBeVisible(); + }); }); diff --git a/docs/APIRef.ActionsOnElement.md b/docs/APIRef.ActionsOnElement.md index 2c7be12670..8c10863688 100644 --- a/docs/APIRef.ActionsOnElement.md +++ b/docs/APIRef.ActionsOnElement.md @@ -12,6 +12,7 @@ Use [expectations](APIRef.Expect.md) to verify element states. - [`.longPressAndDrag()`](#longpressanddragduration-normalizedpositionx-normalizedpositiony-targetelement-normalizedtargetpositionx-normalizedtargetpositiony-speed-holdduration--ios-only) **iOS only** - [`.swipe()`](#swipedirection-speed-normalizedoffset-normalizedstartingpointx-normalizedstartingpointy) - [`.pinch()`](#pinchscale-speed-angle--ios-only) **iOS only** +- [`.scrollToIndex()`](#scrolltoindexindex--android-only) **Android only** - [`.scroll()`](#scrolloffset-direction-startpositionx-startpositiony) - [`whileElement()`](#whileelementelement) - [`.scrollTo()`](#scrolltoedge) @@ -106,6 +107,15 @@ await element(by.id('PinchableScrollView')).pinch(1.1); //Zooms in a little bit await element(by.id('PinchableScrollView')).pinch(2.0); //Zooms in a lot await element(by.id('PinchableScrollView')).pinch(0.001); //Zooms out a lot ``` +### `scrollToIndex(index)` Android only + +Scrolls until it reaches the element with the provided index. + +`index`—the index of the target element
+ +```js +await element(by.id('scrollView')).scrollToIndex(0); +``` ### `scroll(offset, direction, startPositionX, startPositionY)` Simulates a scroll on the element with the provided options. @@ -318,4 +328,4 @@ Simulates a pinch on the element with the provided options. ```js await element(by.id('PinchableScrollView')).pinchWithAngle('outward', 'slow', 0); -``` \ No newline at end of file +``` From c0992c77479e6d2c8baa898d2164609825b3f70e Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Tue, 22 Jun 2021 16:40:12 +0300 Subject: [PATCH 2/9] update docs --- docs/APIRef.ActionsOnElement.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/APIRef.ActionsOnElement.md b/docs/APIRef.ActionsOnElement.md index 8c10863688..e0e1bea184 100644 --- a/docs/APIRef.ActionsOnElement.md +++ b/docs/APIRef.ActionsOnElement.md @@ -109,7 +109,7 @@ await element(by.id('PinchableScrollView')).pinch(0.001); //Zooms out a lot ``` ### `scrollToIndex(index)` Android only -Scrolls until it reaches the element with the provided index. +Scrolls until it reaches the element with the provided index. This works for ReactScrollView and ReactHorizontalScrollView. `index`—the index of the target element
From 65ae00ead6e786b04e9b0a210998bac1ce7ea73d Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Wed, 23 Jun 2021 16:51:15 +0300 Subject: [PATCH 3/9] coverage for scrollToIndex --- detox/index.d.ts | 4 ++++ detox/src/android/AndroidExpect.test.js | 1 + detox/src/android/actions/native.js | 8 -------- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/detox/index.d.ts b/detox/index.d.ts index 6380f2342c..1cb26a88a0 100644 --- a/detox/index.d.ts +++ b/detox/index.d.ts @@ -1032,6 +1032,10 @@ declare global { startPositionY?: number, ): Promise; + /** + * Scroll to index. + * @example await element(by.id('scrollView')).scrollToIndex(10); + */ scrollToIndex( index: Number ): Promise; diff --git a/detox/src/android/AndroidExpect.test.js b/detox/src/android/AndroidExpect.test.js index ea1562e03a..0ff4a8570d 100644 --- a/detox/src/android/AndroidExpect.test.js +++ b/detox/src/android/AndroidExpect.test.js @@ -189,6 +189,7 @@ describe('AndroidExpect', () => { await e.element(e.by.id('ScrollView161')).scrollTo('top'); await e.element(e.by.id('ScrollView161')).scrollTo('left'); await e.element(e.by.id('ScrollView161')).scrollTo('right'); + await e.element(e.by.id('ScrollView161')).scrollToIndex(0); }); it('should not scroll given bad args', async () => { diff --git a/detox/src/android/actions/native.js b/detox/src/android/actions/native.js index e4fabb85a2..6543b766ea 100644 --- a/detox/src/android/actions/native.js +++ b/detox/src/android/actions/native.js @@ -88,14 +88,6 @@ class ScrollEdgeAction extends Action { } } -class ScrollToIndexAction extends Action { - constructor(index) { - super(); - - this._call = invoke.callDirectly(DetoxActionApi.scrollToIndex(index)); - } -} - class SwipeAction extends Action { constructor(direction, speed, normalizedSwipeOffset, normalizedStartingPointX, normalizedStartingPointY) { super(); From 68d65bae799efbe4db0fe3adef9f16522fdfdc55 Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Thu, 24 Jun 2021 14:33:11 +0300 Subject: [PATCH 4/9] Fix unit tests --- .../espresso/scroll/FlinglessSwiperSpec.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt index ba6a24ca88..0274c7c6f0 100644 --- a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt +++ b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt @@ -66,10 +66,10 @@ object FlinglessSwiperSpec: Spek({ } describe("move") { - val SWIPER_VELOCITY = 85f + val SWIPER_VELOCITY = 99f beforeEachTest { - whenever(viewConfig.scaledMinimumFlingVelocity).doReturn(100) // i.e. we expect the swiper to apply a safety margin of 85%, hence actual velocity = 85 px/sec + whenever(viewConfig.scaledMinimumFlingVelocity).doReturn(100) // i.e. we expect the swiper to apply a safety margin of 99%, hence actual velocity = 99 px/sec } it("should obtain a move event") { @@ -121,7 +121,7 @@ object FlinglessSwiperSpec: Spek({ with(uut()) { startAt(0f, 0f) - moveTo(0f, 42.5f) + moveTo(0f, SWIPER_VELOCITY/2) } verify(motionEvents).obtainMoveEvent(any(), eq(expectedEventTime), any(), any()) @@ -151,17 +151,17 @@ object FlinglessSwiperSpec: Spek({ } it("should optimize by applying fling-speed limitation only in last 25% of events") { - whenever(moveEvent.y).doReturn(255f) + whenever(moveEvent.y).doReturn(SWIPER_VELOCITY * 99) - with(uut(expectedMotions = 4)) { + with(uut(expectedMotions = 100)) { startAt(0f, 0f) - moveTo(0f, 85f) - moveTo(0f, 170f) - moveTo(0f, 255f) - moveTo(0f, 340f) + + for (i in 1..100) { + moveTo(0f, SWIPER_VELOCITY * i) + } } - verify(motionEvents, times(3)).obtainMoveEvent(any(), eq(swipeStartTime + 10L), any(), any()) + verify(motionEvents, times(99)).obtainMoveEvent(any(), eq(swipeStartTime + 10L), any(), any()) verify(motionEvents, times(1)).obtainMoveEvent(any(), eq(swipeStartTime + 1000L), any(), any()) } } @@ -190,9 +190,9 @@ object FlinglessSwiperSpec: Spek({ with(uut()) { startAt(666f, 999f) - finishAt(666f + 85f, 999f + 85f) + finishAt(666f + 99f, 999f + 99f) } - verify(motionEvents).obtainUpEvent(downEvent, expectedEventTime, 666f + 85f, 999f + 85f) + verify(motionEvents).obtainUpEvent(downEvent, expectedEventTime, 666f + 99f, 999f + 99f) } it("should finish by flushing all events to ui controller") { From d1ef8050fe132eaa541135301de8d284fbb9b4da Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Thu, 24 Jun 2021 14:33:55 +0300 Subject: [PATCH 5/9] fix test title --- .../java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt index 0274c7c6f0..376c542725 100644 --- a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt +++ b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt @@ -150,7 +150,7 @@ object FlinglessSwiperSpec: Spek({ verify(motionEvents).obtainMoveEvent(any(), eq(expectedEventTime), any(), any()) } - it("should optimize by applying fling-speed limitation only in last 25% of events") { + it("should optimize by applying fling-speed limitation only in last 1% of events") { whenever(moveEvent.y).doReturn(SWIPER_VELOCITY * 99) with(uut(expectedMotions = 100)) { From 4252d99825cf8191470b7e03457e115c9490d5ca Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Sun, 27 Jun 2021 11:00:59 +0300 Subject: [PATCH 6/9] revert fast_events_ratio --- .../detox/espresso/scroll/FlinglessSwiper.kt | 2 +- .../espresso/scroll/FlinglessSwiperSpec.kt | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt index b69ecc3ac9..c43c35ce1e 100644 --- a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt +++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/FlinglessSwiper.kt @@ -93,6 +93,6 @@ class FlinglessSwiper @JvmOverloads constructor( companion object { // private const val LOG_TAG = "DetoxBatchedSwiper" private const val VELOCITY_SAFETY_RATIO = .99f - private const val FAST_EVENTS_RATIO = .99f + private const val FAST_EVENTS_RATIO = .75f } } diff --git a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt index 376c542725..a790df23b0 100644 --- a/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt +++ b/detox/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/FlinglessSwiperSpec.kt @@ -150,19 +150,19 @@ object FlinglessSwiperSpec: Spek({ verify(motionEvents).obtainMoveEvent(any(), eq(expectedEventTime), any(), any()) } - it("should optimize by applying fling-speed limitation only in last 1% of events") { - whenever(moveEvent.y).doReturn(SWIPER_VELOCITY * 99) + it("should optimize by applying fling-speed limitation only in last 25% of events") { + whenever(moveEvent.y).doReturn(255f) - with(uut(expectedMotions = 100)) { + with(uut(expectedMotions = 4)) { startAt(0f, 0f) - - for (i in 1..100) { - moveTo(0f, SWIPER_VELOCITY * i) - } + moveTo(0f, 85f) + moveTo(0f, 170f) + moveTo(0f, 255f) + moveTo(0f, 340f) } - verify(motionEvents, times(99)).obtainMoveEvent(any(), eq(swipeStartTime + 10L), any(), any()) - verify(motionEvents, times(1)).obtainMoveEvent(any(), eq(swipeStartTime + 1000L), any(), any()) + verify(motionEvents, times(3)).obtainMoveEvent(any(), eq(swipeStartTime + 10L), any(), any()) + verify(motionEvents, times(1)).obtainMoveEvent(any(), eq(swipeStartTime + 858), any(), any()) } } } From 49035cc4ecc511152e9a336749fae456ffd4e578 Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Sun, 27 Jun 2021 14:44:22 +0300 Subject: [PATCH 7/9] rename class to action --- .../src/full/java/com/wix/detox/espresso/DetoxAction.java | 4 ++-- .../action/{ScrollToIndex.kt => ScrollToIndexAction.kt} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename detox/android/detox/src/main/java/com/wix/detox/espresso/action/{ScrollToIndex.kt => ScrollToIndexAction.kt} (98%) diff --git a/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java b/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java index cf6d93381e..00a2c3a415 100644 --- a/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +++ b/detox/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java @@ -7,7 +7,7 @@ import com.wix.detox.espresso.action.DetoxMultiTap; import com.wix.detox.espresso.action.RNClickAction; import com.wix.detox.espresso.action.ScreenshotResult; -import com.wix.detox.espresso.action.ScrollToIndex; +import com.wix.detox.espresso.action.ScrollToIndexAction; import com.wix.detox.espresso.action.TakeViewScreenshotAction; import com.wix.detox.espresso.action.GetAttributesAction; import com.wix.detox.action.common.MotionDir; @@ -145,7 +145,7 @@ public static ViewAction getAttributes() { } public static ViewAction scrollToIndex(int index) { - return new ScrollToIndex(index); + return new ScrollToIndexAction(index); } public static ViewAction takeViewScreenshot() { diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndexAction.kt similarity index 98% rename from detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt rename to detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndexAction.kt index b5b45f380c..65f37cd804 100644 --- a/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndex.kt +++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/ScrollToIndexAction.kt @@ -16,7 +16,7 @@ import com.wix.detox.espresso.scroll.ScrollHelper import org.hamcrest.Matcher import org.hamcrest.Matchers -class ScrollToIndex(private val index: Int) : ViewAction { +class ScrollToIndexAction(private val index: Int) : ViewAction { override fun getConstraints(): Matcher { return Matchers.anyOf( Matchers.allOf( From 73a5b1c76958cf975af62be79eb8f01558431c8b Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Sun, 27 Jun 2021 15:31:44 +0300 Subject: [PATCH 8/9] change scrollToIndex to android only --- detox/test/e2e/03.actions-scroll.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detox/test/e2e/03.actions-scroll.test.js b/detox/test/e2e/03.actions-scroll.test.js index 09e5e74b8b..251a2ca8b5 100644 --- a/detox/test/e2e/03.actions-scroll.test.js +++ b/detox/test/e2e/03.actions-scroll.test.js @@ -72,7 +72,7 @@ describe('Actions - Scroll', () => { await expect(element(by.text('HText6'))).not.toBeVisible(); }); - it('should be able to scrollToIndex on horizontal scrollviews', async () => { + it(':android: should be able to scrollToIndex on horizontal scrollviews', async () => { // should ignore out of bounds children await element(by.id('ScrollViewH')).scrollToIndex(3000); await element(by.id('ScrollViewH')).scrollToIndex(-1); @@ -88,7 +88,7 @@ describe('Actions - Scroll', () => { await expect(element(by.text('HText8'))).not.toBeVisible(); }); - it('should be able to scrollToIndex on vertical scrollviews', async () => { + it(':android: should be able to scrollToIndex on vertical scrollviews', async () => { // should ignore out of bounds children await element(by.id('ScrollView161')).scrollToIndex(3000); await element(by.id('ScrollView161')).scrollToIndex(-1); From a5f9b456994d8f0c50f5bd2db6c37cd2715b64bc Mon Sep 17 00:00:00 2001 From: jonathanmos Date: Wed, 30 Jun 2021 10:24:46 +0300 Subject: [PATCH 9/9] remove not visible checks to deal with viewable area issue --- detox/test/e2e/03.actions-scroll.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/detox/test/e2e/03.actions-scroll.test.js b/detox/test/e2e/03.actions-scroll.test.js index 251a2ca8b5..738c5bb8f9 100644 --- a/detox/test/e2e/03.actions-scroll.test.js +++ b/detox/test/e2e/03.actions-scroll.test.js @@ -96,11 +96,9 @@ describe('Actions - Scroll', () => { await element(by.id('ScrollView161')).scrollToIndex(11); await expect(element(by.text('Text12'))).toBeVisible(); - await expect(element(by.text('Text1'))).not.toBeVisible(); await element(by.id('ScrollView161')).scrollToIndex(0); await expect(element(by.text('Text1'))).toBeVisible(); - await expect(element(by.text('Text12'))).not.toBeVisible(); await element(by.id('ScrollView161')).scrollToIndex(7); await expect(element(by.text('Text8'))).toBeVisible();