wix / Detox

Gray box end-to-end testing and automation framework for mobile apps

Home Page:https://wix.github.io/Detox/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Android API 32, 33 (v12): .tap() acts like tap+hold

sergtimosh opened this issue · comments

What happened?

When detox tests executed against devices/emulators with API 33 level .tap() function acts like tap + hold(unreleased tap)

What was the expected behaviour?

tap should release

Was it tested on latest Detox?

  • I have tested this issue on the latest Detox release and it still reproduces.

Did your test throw out a timeout?

Help us reproduce this issue!

No response

In what environment did this happen?

Detox version: 20.1.0
React Native version: 0.68.2
Node version: 16.14.0
Device model: pixel 6a
Android version: 12
Test-runner (select one): jest

Device logs

12-17 00:01:06.220 19686 19765 I DetoxWSClient: Sending out action 'ready' (ID #-1000)
12-17 00:01:06.221 19686 19765 I DetoxDispatcher: Done with action 'isReady'
12-17 00:01:06.221 19686 19765 I DetoxDispatcher: Handling action 'loginSuccess' (ID #0)...
12-17 00:01:06.221 19686 19765 I DetoxDispatcher: Done with action 'loginSuccess'
12-17 00:01:06.221 19686 19765 I DetoxDispatcher: Handling action 'isReady' (ID #-1000)...
12-17 00:01:06.222 19686 19686 I Detox   : Wait is over: App is now idle!
12-17 00:01:06.222 19686 19765 I DetoxWSClient: Sending out action 'ready' (ID #-1000)
12-17 00:01:06.222 19686 19765 I DetoxDispatcher: Done with action 'isReady'
12-17 00:01:06.278  1543  2314 D ConnectivityService: NetReassign [no changes]
12-17 00:01:06.667 19686 19694 I ftware.template: Background concurrent copying GC freed 235840(11MB) AllocSpace objects, 22(94MB) LOS objects, 76% free, 7661KB/31MB, paused 120us,48us total 151.410ms
12-17 00:01:07.243 19686 19767 D DetoxWSClient: Received action 'invoke' (ID #1, params={"target":{"type":"Class","value":"com.wix.detox.espresso.EspressoDetox"},"method":"perform","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"androidx.test.espresso.Espresso"},"method":"onView","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForAtIndex","args":[{"type":"Integer","value":0},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForTestId","args":["plus-icon"]}}]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxAction"},"method":"tapAtLocation","args":[{"type":"Integer","value":5},{"type":"Integer","value":10}]}}]})
12-17 00:01:07.243 19686 19765 I DetoxDispatcher: Handling action 'invoke' (ID #1)...
12-17 00:01:07.245 19686 19765 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForTestId, [plus-icon]
12-17 00:01:07.249 19686 19765 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForAtIndex, [0, (view.getTag() is "plus-icon" and view has effective visibility <VISIBLE>)]
12-17 00:01:07.251 19686 19765 D Detox   : class androidx.test.espresso.Espresso, onView, [View at index #0, of those matching MATCHER(view.getTag() is "plus-icon" and view has effective visibility <VISIBLE>)]
12-17 00:01:07.252 19686 19765 D Detox   : class com.wix.detox.espresso.DetoxAction, tapAtLocation, [5, 10]
12-17 00:01:07.254 19686 19765 D Detox   : class com.wix.detox.espresso.EspressoDetox, perform, [androidx.test.espresso.ViewInteraction@cc2fd4f, com.wix.detox.espresso.action.RNClickAction@24e1cdc]
12-17 00:01:07.272 19686 19686 I ViewInteraction: Performing 'com.wix.detox.espresso.action.detoxsingletap@e7a44ba click' action on view View at index #0, of those matching MATCHER(view.getTag() is "plus-icon" and view has effective visibility <VISIBLE>)
...
12-17 00:01:07.850 19686 19765 I DetoxWSClient: Sending out action 'invokeResult' (ID #1)
12-17 00:01:07.851 19686 19765 I DetoxDispatcher: Done with action 'invoke'
12-17 00:01:09.402  1543  2314 D ConnectivityService: NetReassign [no changes]

another tap() example

12-17 00:16:20.949 26520 26599 I DetoxWSClient: Sending out action 'invokeResult' (ID #3)
12-17 00:16:20.949 26520 26599 I DetoxDispatcher: Done with action 'invoke'
12-17 00:16:20.958 26520 26601 D DetoxWSClient: Received action 'invoke' (ID #4, params={"target":{"type":"Class","value":"com.wix.detox.espresso.EspressoDetox"},"method":"perform","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"androidx.test.espresso.Espresso"},"method":"onView","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForText","args":["Login"]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxViewActions"},"method":"click","args":[]}}]})
12-17 00:16:20.959 26520 26599 I DetoxDispatcher: Handling action 'invoke' (ID #4)...
12-17 00:16:20.959 26520 26599 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForText, [Login]
12-17 00:16:20.960 26520 26599 D Detox   : class androidx.test.espresso.Espresso, onView, [(an instance of android.widget.TextView and view.getText() with or without transformation to match: is "Login" and view has effective visibility <VISIBLE>)]
12-17 00:16:20.960 26520 26599 D Detox   : class com.wix.detox.espresso.DetoxViewActions, click, []
12-17 00:16:20.960 26520 26599 D Detox   : class com.wix.detox.espresso.EspressoDetox, perform, [androidx.test.espresso.ViewInteraction@a34ad82, com.wix.detox.espresso.action.RNClickAction@9d7ac93]

I'm also seeing this issue on Android API 33.
Detox will find the element and on calling tap, the button shows as though its held down. The logs all seem to show that the step fired the click/tap successfully but of course the next step will fail

Detox version: 20.1.0
React Native version: 0.70.6

12-20 13:51:32.072 10094 10259 I DetoxDispatcher: Handling action 'invoke' (ID #2)...
12-20 13:51:32.072 10094 10259 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForTestId, [onboarding-sign-up]
12-20 13:51:32.072 10094 10259 D Detox   : class androidx.test.espresso.Espresso, onView, [(view.getTag() is "onboarding-sign-up" and view has effective visibility <VISIBLE>)]
12-20 13:51:32.072 10094 10259 D Detox   : class com.wix.detox.espresso.DetoxViewActions, click, []
12-20 13:51:32.073 10094 10259 D Detox   : class com.wix.detox.espresso.EspressoDetox, perform, [androidx.test.espresso.ViewInteraction@578a4a3, com.wix.detox.espresso.action.RNClickAction@f99f3a0]
12-20 13:51:32.075 10094 10094 I ViewInteraction: Performing 'com.wix.detox.espresso.action.detoxsingletap@a87ab59 click' action on view (view.getTag() is "onboarding-sign-up" and view has effective visibility <VISIBLE>)
12-20 13:51:32.104 10094 10161 D EGL_emulation: app_time_stats: avg=514.85ms min=1.26ms max=3066.95ms count=6
12-20 13:51:32.601 10094 10259 I DetoxWSClient: Sending out action 'invokeResult' (ID #2)
12-20 13:51:32.602 10094 10259 I DetoxDispatcher: Done with action 'invoke'
12-20 13:51:32.608 10094 10261 D DetoxWSClient: Received action 'invoke' (ID #3, params={"target":{"type":"Class","value":"com.wix.detox.espresso.EspressoDetox"},"method":"perform","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"androidx.test.espresso.Espresso"},"method":"onView","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForTestId","args":["onboarding-phone"]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxViewActions"},"method":"click","args":[]}}]})
12-20 13:51:32.608 10094 10259 I DetoxDispatcher: Handling action 'invoke' (ID #3)...
12-20 13:51:32.608 10094 10259 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForTestId, [onboarding-phone]
12-20 13:51:32.608 10094 10259 D Detox   : class androidx.test.espresso.Espresso, onView, [(view.getTag() is "onboarding-phone" and view has effective visibility <VISIBLE>)]
12-20 13:51:32.608 10094 10259 D Detox   : class com.wix.detox.espresso.DetoxViewActions, click, []
12-20 13:51:32.609 10094 10259 D Detox   : class com.wix.detox.espresso.EspressoDetox, perform, [androidx.test.espresso.ViewInteraction@6cc051b, com.wix.detox.espresso.action.RNClickAction@c4e96b8]
12-20 13:51:32.618 10094 10259 I DetoxActionHandlers: Test exception

UPDATE: longPress does not have the same issue however multiTap does

@AdamTyler Thanks for the confirmation. I was trying to find the way of how theoretically I can overcome this with other tap methods and longPress() can help, but not for every element. If the element is listening for longPress() it will act like longPress() was fired even with longPress(1) .

I am seeing the same issue across two different projects with:

  • Detox 19.2.6 + React Native 0.70.2
  • Detox 20.1.0 + React Native 0.69.1

@sergtimosh @AdamTyler @fossage We would very much appreciate a reproduction using DetoxTemplate so we could better inspect this. In essence, we've seen the various tap()'s working properly on recent Android versions.

I can confirm I had the same issue. tap() and typeText() did not work for me.

  • Detox 20.1.1 + React Native 0.70.3

I was using emulator with API 33 - that was causing all the trouble.
Changed to API 31 - now everything works as expected.

@d4vidi just checked with DetoxTemplate and API 33 system image and it's failing there too.

You can check the screencast below. I've just added 2s timeouts before and after tap() so it's clearly visible that element isn't released.
https://www.screencast.com/t/GGyBN9iBuNGs

I am seeing the same issue on Detox 20.1.1 + React Native 0.67.4

Also using API 31 on emulator made it work

I'm triaging, and will report ASAP.

I can approve this reproduces clearly with API v33. Presumably, something in Detox's tap-untap events injection fails to execute properly in a system running the recent API. Perhaps upgrading Espresso (3.4.0 -> 3.5.1) could fix this seamlessly (even though I didn't see anything related in their release notes); @sergtimosh would you be willing to try that?

@d4vidi just tried to build my fork with Espresso upgraded to (3.5.1) and got build failure(the 3.4.0 builds fine). Anyway I don't feel enough competent to dig down into this.

> Task :detox:compileFullReleaseJavaWithJavac FAILED
/Users/serhiytymoshenko/work/proj/Detox/detox/android/detox/src/full/java/com/wix/detox/espresso/assertion/ViewAssertions.java:28: error: incompatible types: Object cannot be converted to Matcher<? super View>
        return new MatchesViewAssertion(checkNotNull(viewMatcher));
                                                    ^
Note: /Users/serhiytymoshenko/work/proj/Detox/detox/android/detox/src/full/java/com/wix/detox/Detox.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':detox:compileFullReleaseJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

@sergtimosh have you had any luck on this issue? I am running into the same problem. I can confirm that downgrading to 31 works for the emulator; however, I would like to run some of my tests on a physical android device that is running 32, and I am still seeing the tap holding.

@hkaras19 no I had no luck with suggestion from @d4vidi.

@d4vidi just tried to build my fork with Espresso upgraded to (3.5.1) and got build failure(the 3.4.0 builds fine). Anyway I don't feel enough competent to dig down into this.

> Task :detox:compileFullReleaseJavaWithJavac FAILED
/Users/serhiytymoshenko/work/proj/Detox/detox/android/detox/src/full/java/com/wix/detox/espresso/assertion/ViewAssertions.java:28: error: incompatible types: Object cannot be converted to Matcher<? super View>
        return new MatchesViewAssertion(checkNotNull(viewMatcher));
                                                    ^
Note: /Users/serhiytymoshenko/work/proj/Detox/detox/android/detox/src/full/java/com/wix/detox/Detox.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':detox:compileFullReleaseJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

Apparently Espresso 3.5.1 comes with some API changes / deprecations removal. I doubt we would be able to get into this in the near future - would appreciate a more thorough attempt.

We are likely to address this within the upcoming 1-2 months.

commented

I think I have the same issue running our test suite. The interesting thing is it will consistently fail this way on our CI (EAS) and consistently pass on my local machine. Both running on an emulator with the same API 32 config. I'm not familiar enough to debug it further myself but let me know if I can assist by sharing specific logs or other information.

Thanks @isilher, I'm hopeful that once we find the root cause for this, we could explain why that is.

Same issue with:

"detox": "^20.5.0"
"react-native": "^0.71.6"
Android API 33

@d4vidi facing the same on latest react native and detox, on tapping the button doesn't get released in the Pixel 3a API 33

same issue with:
"react-native": "0.70.5",
"detox": "^20.6.0",
Android API 31

commented

same issue here
API 33
RN 0.70.5
Detox 20.1.3

I tested on API 31 and still have this issue
RN 0.71.0
Detox 20.7.0

I'm encountering this issue as well. The iOS simulator works fine. My physical and emulated Android devices show the same pressed-and-held problem.
API: 33
RN: 0.70.8
Detox: 20.7.1

Same issue here:
RN: 0.71.7
Detox: 20.7.0

Android Emulator:
API 31 --> works
API 32/33 --> fails

commented

Thank you everyone, for your reports 🙏🏻

We are fairly low on resources on the Android side ATM, and would highly appreciate any extra effort taken by the community in getting this fixed or at least in finding the root cause.

how's it going? it block testing in android 13, or other workaround to bypass it?

UPDATE: markpar is correct, I can still run Detox with target at SDK 33, just won't be able to run the tests on the 2 most recent SDKs until this is resolved.

------- original comment ----

Hi Detox team- I understand you are low on resources but this needs to be prioritized or no one is going to be able to use Detox on Android as of August 2023 for any apps as Google is mandating app developers raise their target SDK to 33+. The recommended workaround of dropping the SDK level will no longer be allowed by Google.

Starting on August 31, 2023:

    New apps must target Android 13 (API level 33) or higher; except for [Wear OS](https://developer.android.com/wear) apps, which must target a version between Android 11 (API level 30) and Android 13 (API level 33), inclusive.

    App updates must target Android 13 or higher and adjust for behavioral changes in Android 13; except for Wear OS apps, which must target Android 11.

Permanently private apps—which are restricted to users in a specific organization and are intended for internal distribution only—aren't required to meet the target API level requirements.

Source:
https://developer.android.com/google/play/requirements/target-sdk

Hi Detox team- I understand you are low on resources but this needs to be prioritized or no one is going to be able to use Detox on Android as of August 2023 ...

It is true that Google mandates a target SDK version of 33, but that doesn't necessarily mean the app won't run on earlier/older SDK versions. Our React Native app targets SDK 33 and runs just fine on Android 11 (SDK 30).

happening here

API 31
detox 20.9.1
RN 0.72.3

happening here

API 31 detox 20.9.1 RN 0.72.3

I am also having this problem with detox 20.11.1 and react-native 7.2.3

Hello, i am also having the same issue

API 33
Detox 20.11.2
RN 0.72.1

the same error

Yes, this issue is blocking testing

API 32/33
Detox 20.11.2
RN 0.70.5

hey @d4vidi any updates on this one?

Hi 👋🏻 I was wondering if anyone has ideas on how hard this would be to fix. Is this something that someone without deep understanding of the library and/or Android can attempt to fix? Did someone of the maintainers team already attempted a fix or can provide any clues on where the problem might be for external contributors to give it a try?

We run our Detox tests in real physical devices and its going to be hard for us to keep using Android 12 for long (as we want to keep our tests close to the real field usage which is mostly Android 13). The longPress/Tap workaround is also not an option as we use those two actions in different ways in different parts of the app.

Any comments or other potential workarounds are appreciated ☺️

Thank you very much!

@sdurandeu I didn't get time to look into this, but a quick workaround that helped me was to replace .tap() calls with .longPress(400) calls, this simulates a long press but fast enough to be a tap. until someone, or I get some time to dig further.

I noticed "similar?" issues with with react-native-screens and reanimated 3 causing this to actually happen on real devices with actually tapping buttons by hand would trigger onPressIn and onPressOut almost simultaneously, causing buttons to not work intermittently 🤷 , but I hope this gets your tests working until this is sorted out!

Note: the press duration is iOS only , but I keep it to allow the test to be usable for both platforms.

Experiencing this issue also as a result of upping my target API to 33 due to new Play Store limitations.

commented

Thank you everyone, for your reports 🙏🏻

We are fairly low on resources on the Android side ATM, and would highly appreciate any extra effort taken by the community in getting this fixed or at least in finding the root cause.

Thanks again for reporting. This statement still holds true. We would very much value the community stepping up for getting this fixed. This is a good place to start the debugging from 🙏🏻

Hello, thank you for maintaining Detox, it's a great library.

Unfortunately, experiencing this as well on API 33. Is there any news on this?

Blocking android on

API 34
Detox 20.12.0
RN 0.71.4

I have same on

  • Android 33
  • Detox 20.9.1
  • React native 0.72.0

This is very crucial bug!

commented

Also facing this issue. longPress() does work as a workaround, however I need tap({x:5, y:10}) with coordinates which I cannot do with longPress().

Any idea what might be causes the issue with the Android sdk? It seems like espresso is not up-to-date? Maybe updating espresso-core to 3.5.1 solves some issues?

As pointed out by d4vid, the root cause seems to be linked to the custom DetoxMultiTap implementation. I've found a temporary solution by using the standard espresso Tap.SINGLE instead of DetoxMultiTap. Please refer to the attached patch file for details.

However, this approach does have its drawbacks. As discussed in DetoxMultiTap, this change introduces some timing inconsistencies, particularly taps being misinterpreted as long taps. For my specific application, which doesn't utilize long tap handlers, the Tap.SINGLE solution is satisfactory for now.

I intend to delve deeper into the DetoxMultiTap issues and try to resolve them when I can. However, I'm quite pressed for time at the moment. It would be greatly appreciated if someone else could also investigate this in the interim.

diff --git a/node_modules/detox/android/detox/src/full/java/com/wix/detox/espresso/action/RNClickAction.java b/node_modules/detox/android/detox/src/full/java/com/wix/detox/espresso/action/RNClickAction.java
index 68bf039..8a617f9 100644
--- a/node_modules/detox/android/detox/src/full/java/com/wix/detox/espresso/action/RNClickAction.java
+++ b/node_modules/detox/android/detox/src/full/java/com/wix/detox/espresso/action/RNClickAction.java
@@ -14,6 +14,7 @@ import androidx.test.espresso.action.CoordinatesProvider;
 import androidx.test.espresso.action.GeneralClickAction;
 import androidx.test.espresso.action.GeneralLocation;
 import androidx.test.espresso.action.Press;
+import androidx.test.espresso.action.Tap;
 
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
 
@@ -22,7 +23,7 @@ public class RNClickAction implements ViewAction {
 
     public RNClickAction() {
         clickAction = new GeneralClickAction(
-                        new DetoxSingleTap(),
+                        Tap.SINGLE,
                         GeneralLocation.VISIBLE_CENTER,
                         Press.FINGER,
                         InputDevice.SOURCE_UNKNOWN,
@@ -31,7 +32,7 @@ public class RNClickAction implements ViewAction {
 
     public RNClickAction(CoordinatesProvider coordinatesProvider) {
         clickAction = new GeneralClickAction(
-                        new DetoxSingleTap(),
+                        Tap.SINGLE,
                         coordinatesProvider,
                         Press.FINGER,
                         InputDevice.SOURCE_UNKNOWN,

(Tested on Android 34)

This patch seems to fix the issue. I updated obtainUpEvent in com.wix.detox.espresso.action.common.MotionEvent to match more closely the implementation of obtainUpEvent in androidx.test.espresso.action.MotionEvents.

Can someone confirm?
Patch should be easy to apply on Detox 20.13.0 with patch-package

Patch
diff --git a/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt b/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
index 1a8e1d7..48b9233 100644
--- a/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
+++ b/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
@@ -13,7 +13,7 @@ class MotionEvents {
             = MotionEvents.obtainMovement(downEvent.downTime, eventTime, floatArrayOf(x, y))!!
 
     fun obtainDownEvent(x: Float, y: Float, precision: FloatArray = PRECISION)
-        = obtainDownEvent(x, y, precision, null)
+            = obtainDownEvent(x, y, precision, null)
 
     fun obtainDownEvent(x: Float, y: Float, precision: FloatArray = PRECISION, _downTime: Long?): MotionEvent {
         val pointerProperties = MotionEvent.PointerProperties().apply {
@@ -30,24 +30,51 @@ class MotionEvents {
         val downTime = _downTime ?: SystemClock.uptimeMillis()
 
         return MotionEvent.obtain(
-                downTime,
-                downTime,
-                MotionEvent.ACTION_DOWN,
-                1,
-                arrayOf(pointerProperties),
-                arrayOf(pointerCoords),
-                0,
-                MotionEvent.BUTTON_PRIMARY,
-                precision[0],
-                precision[1],
-                0,
-                0,
-                InputDevice.SOURCE_UNKNOWN,
-                0)
+            downTime,
+            downTime,
+            MotionEvent.ACTION_DOWN,
+            1,
+            arrayOf(pointerProperties),
+            arrayOf(pointerCoords),
+            0,
+            MotionEvent.BUTTON_PRIMARY,
+            precision[0],
+            precision[1],
+            0,
+            0,
+            InputDevice.SOURCE_UNKNOWN,
+            0)
     }
 
-    fun obtainUpEvent(downEvent: MotionEvent, eventTime: Long, x: Float, y: Float): MotionEvent
-            = MotionEvent.obtain(downEvent.downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0)!!
+    fun obtainUpEvent(downEvent: MotionEvent, eventTime: Long, x: Float, y: Float): MotionEvent {
+        val pointerProperties = MotionEvent.PointerProperties().apply {
+            id = 0
+            toolType = MotionEvent.TOOL_TYPE_UNKNOWN
+        }
+        val pointerCoords = MotionEvent.PointerCoords().apply {
+            clear()
+            this.x = x
+            this.y = y
+            this.pressure = 0f
+            this.size = 1f
+        }
+        return MotionEvent.obtain(
+            downEvent.downTime,
+            eventTime,
+            MotionEvent.ACTION_UP,
+            1, // pointerCounts
+            arrayOf(pointerProperties),
+            arrayOf(pointerCoords),
+            0, // metaState
+            downEvent.buttonState,
+            downEvent.xPrecision,
+            downEvent.yPrecision,
+            0, // deviceId
+            0, // edgeFlags
+            downEvent.source,
+            0
+        )
+    }
 
     fun sendDownAsync(uiController: UiController, x: Float, y: Float, precision: FloatArray = PRECISION): MotionEvent {
         val downEvent = obtainDownEvent(x, y, precision, null)

@ericschaal (🏆 thanks for your patch), @gomesbreno, @sdurandeu, @mostafaberg, @AdamTyler, @isilher, @otech47, @markpar, @sunchanras, @fossage, @catanet, @d4vidi, @jeroen-van-dijk, @BBKolton, @AnisDerbel, @cortisiko, @FadiAboMsalam, @Rednegniw, @programystic-dev, @ShivamJoker, @dooleyb1, @cpham-groundswell, @sergtimosh, @arthwood, @zwerg44, @andac-ozcan, @otoniel-isidoro, @manuquentin, @codexico, @nateshmbhat, @vjdhanota, @raldred.

The patched version is available as detox@20.13.1-smoke.0 on NPM.

Could you please verify if the fix works and if there are any undesirable side effects?
We'll release the fix next Thursday if no negative feedback (e.g. regressions, etc.) is received.

Could you please verify if the fix works and if there are any undesirable side effects?

We'll release the fix next Thursday if no negative feedback (e.g. regressions, etc.) is received.

I'll give that a quick test on Monday morning and report back 👌 great work !

I tried it out and this issue is fixed for my tests and app. However, I'm now running into #2787. 😆

commented

@noomorph Thanks for the support! We tested the patched version and it solved our issues! 🚀

Thanks for the feedback.
In the meantime, we don't see any breakages on our Android tests + older APIs, so I'll likely release it sooner.
Let's plan that for tomorrow.

This unfortunately does not seem to resolve things fully, might cause some confusion, as @markpar mentioned, the swiping does not work.

In our case, we have a global scroller that handles all SectionList, Flatlist & Scrollview components, while looking for a component within any of those, we'll automatically scroll until found.

this behavior is pretty much what makes/breaks the tests since lots of components are outside the screen during e2e tests.

it does fix the tapping though, which is a plus, but I'm not sure if that's ideal 🤔

In my case, adding flex: 1 to the parent container, as described in #2787 (comment) got me past the issue.

Disregard that comment. I was using an Android 11 phone and I thought I was on Android 13. 🤦

@mostafaberg AFAIU, tapping handlers and scrolling handlers are separate pieces of code, so I don't think we should wait for the scrolling fixes to release @ericschaal's patch.

If anyone has time soon to play with the scrolling code and see what changes can fix it, you are welcome – Use patch-package or anything that works for you, test your fix, and if you're sure it works, I'll be available to assist you with beta testing, as we did with @ericschaal last week.

@mostafaberg AFAIU, tapping handlers and scrolling handlers are separate pieces of code, so I don't think we should wait for the scrolling fixes to release @ericschaal's patch.

If anyone has time soon to play with the scrolling code and see what changes can fix it, you are welcome – Use patch-package or anything that works for you, test your fix, and if you're sure it works, I'll be available to assist you with beta testing, as we did with @ericschaal last week.

You're 100% correct this does fix the tapping issue at least!, maybe leave a small "known issue" note in the release notes to avoid more tickets coming in later 😄

Okay, sure, I'll add that to release note. Thanks for the suggestion!

Overall, I'd be glad to help further with Android 31+ bugs, and maybe eventually I'll do if my team continues to be unavailable for a long time, but as you can see sometimes these fixes are just ±10 lines of code, so I encourage everyone who's comfortable enough with Android to look into it. 🙏 Pull requests from the community remain our top 1 priority, I can assure you'll get reviews and assistance quickly.

Will try to get more time to get this done, my initial approach was to upgrade espresso but I didn't get enough time as it was a bigger change than I could manage at the time :( , might as well find some smaller changes as you recommended and get things rolling 👍

The fix is available in detox@20.13.1.

I was able to get scrolling working with an almost identical patch to what @ericschaal provided.

Unfortunately, swiping is still not working. It might be fixable by implementing a custom swiper instead of relying on the built-in implementations Swipe.FAST and Swipe.SLOW, in case anyone wants to give that a shot.

Patch
diff --git a/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt b/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
index d8fc451..502ad40 100644
--- a/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
+++ b/node_modules/detox/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt
@@ -9,8 +9,37 @@ import androidx.test.espresso.action.MotionEvents
 private val PRECISION = floatArrayOf(16f, 16f)
 
 class MotionEvents {
-    fun obtainMoveEvent(downEvent: MotionEvent, eventTime: Long, x: Float, y: Float): MotionEvent
-            = MotionEvents.obtainMovement(downEvent.downTime, eventTime, floatArrayOf(x, y))!!
+    fun obtainMoveEvent(downEvent: MotionEvent, eventTime: Long, x: Float, y: Float): MotionEvent {
+        val pointerProperties = MotionEvent.PointerProperties().apply {
+            clear()
+            id = 0
+            toolType = MotionEvent.TOOL_TYPE_UNKNOWN
+        }
+        val pointerCoords = MotionEvent.PointerCoords().apply {
+            clear()
+            this.x = x
+            this.y = y
+            this.pressure = 0f
+            this.size = 1f
+        }
+
+        return MotionEvent.obtain(
+              downEvent.downTime,
+              eventTime,
+              MotionEvent.ACTION_MOVE,
+              1, // pointerCounts
+              arrayOf(pointerProperties),
+              arrayOf(pointerCoords),
+              0, // metaState
+              downEvent.buttonState,
+              downEvent.xPrecision,
+              downEvent.yPrecision,
+              0, // deviceId
+              0, // edgeFlags
+              downEvent.source,
+              0
+        )
+    }
 
     fun obtainDownEvent(x: Float, y: Float, precision: FloatArray = PRECISION)
         = obtainDownEvent(x, y, precision, null)