15
onData(anything()).inAdapterView(withId(R.id.ScheduleOrderListViewListView))
                .atPosition(0).perform(click());

perfoms 50% of the time a longtouch - is there are a good workaround?

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
PKAP
  • 705
  • 8
  • 20
  • ye - I dont want him to do a longclick ;) It is like total random if he is doing a click or a longclick – PKAP Sep 01 '15 at 11:52
  • From the GeneralClickAction implementation, you can see that using an overloaded version of click(ViewAction rollbackAction) rather than the default implementation click() can help tracking when the long click has occurred. If rollbackAction is specified then it will be executed if the short click was transformed into the long click. – Anatolii Feb 07 '16 at 23:25

5 Answers5

12

This is an unfortunate side effect of how tap events are passed from your test code over RPC to the Android application under test. The best description of why clicks are sometimes executed as long clicks can be found in the Espresso source code.

It is unlikely this issue will be fixed anytime soon. The best option you have of avoiding the issue is to run your tests on higher spec devices. This is because the likelihood of the issue occurring is dependent on system load.

Charles Harley
  • 7,184
  • 3
  • 32
  • 38
  • 3
    As an additional workaround, try increasing the long press delay values of your test devices/emulators under **Setting -> Accessibility -> Touch & hold delay** – Nick Korostelev May 09 '16 at 16:43
  • Increasing touch & hold doesn't help on Android SDK 26. I even tried to set it to 15 seconds: "adb shell settings put secure long_press_timeout 15000". It just waits 15 secs and perform long click. – sasha_trn Sep 18 '17 at 13:44
  • This seems to be horribly broken. Is this issue already resolved? – Mike76 Oct 07 '19 at 14:06
8

Adding to what Charles said, I found 3 workarounds here: https://github.com/misyobun/android-test-kit/issues/45

Workaround 1: (and maybe the best one) is to pass a rollback action in case the click turns into a long click. In case this happened, the long click would be "cancelled" and espresso will try the click again.

/**
   * Returns an action that performs a single click on the view.
   *
   * If the click takes longer than the 'long press' duration (which is possible) the provided
   * rollback action is invoked on the view and a click is attempted again.
   *
   * This is only necessary if the view being clicked on has some different behaviour for long press
   * versus a normal tap.
   *
   * For example - if a long press on a particular view element opens a popup menu -
   * ViewActions.pressBack() may be an acceptable rollback action.
   *
   * <br>
   * View constraints:
   * <ul>
   * <li>must be displayed on screen</li>
   * <li>any constraints of the rollbackAction</li>
   * <ul>
   */
  public static ViewAction click(ViewAction rollbackAction) {
    checkNotNull(rollbackAction);
    return new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER,
        rollbackAction);
  }

Workaround 2: is not the "espresso way", but it might fit some scenarios:

public class CallOnClickAction implements ViewAction {
    @Override
    public Matcher<View> getConstraints() {
        return allOf(isClickable(), isDisplayed());
    }

    @Override
    public String getDescription() {
        return "CallOnClick";
    }

    @Override
    public void perform(UiController uiController, View view) {
        view.callOnClick();

    }
 }

Workaround 3: If you're not using double click on that view, it might be useful in this case.

Yair Kukielka
  • 10,686
  • 1
  • 38
  • 46
4

Another additional workaround is running the following command on API level > 16

adb shell settings put secure long_press_timeout 1500
Nick Korostelev
  • 325
  • 2
  • 10
1

I had this effect when animations where enabled. Animations must be disabled for espresso

ligi
  • 39,001
  • 44
  • 144
  • 244
0

You may fix this issue in espresso tests with help of UiAutomator. Place this code in your parent tests class:

private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

@Before fun setUp() {
    uiDevice.executeShellCommand("settings put secure long_press_timeout 3000")
}

Put 3000ms because 1500ms was not enough in my case.

SerjantArbuz
  • 982
  • 1
  • 12
  • 16