user3050720
user3050720

Reputation: 553

Espresso AutoCompleteTextView click

So I recently started messing around with Espresso in one of my existing Android projects.

Everything went pretty decently, until I came to find AutoCompleteTextView in my program. I don't seem to understand how to properly click the first thing in the autocomplete list. I'm actually not even sure which to use, onView() or onData() in this instance.

Upvotes: 19

Views: 5249

Answers (7)

aiman
aiman

Reputation: 1

Here is few problem currently i encountered with available solutions :

  • Solution using onView will not work if the item is not visible (need to scroll).
  • AStupidNoob's solution using onData also doesn't work on me.

Here is my workaround using onData with position :

onData(anything())
 .inRoot(RootMatchers.isPlatformPopup())
 .atPosition(itemIndex)
 .perform(click())

In this solution, we can click the item in the list as long we know the position of item.

Upvotes: 0

Ming
Ming

Reputation: 1

Since the place predictions are inside a recyclerview, after typing the name of the placement, if you want to click on the first option in the predicted list, you can go with one of the RecyclerViewActions methods (actionOnItemAtPosition). The key is to find out the id of the autocompleted places. It is set up by Google Place SDK but not yourself so might not be that straightforward to find out. This works for my project, see if it can help: onView(ViewMatchers.withId(com.google.android.libraries.places.R.id.places_autocomplete_list)).perform(RecyclerViewActions.actionOnItemAtPosition(0,click()));

Upvotes: 0

Peter
Peter

Reputation: 463

For anyone still running into this issue, despite trying out the accepted solution above, I managed to get it working with help from a github issue I uncovered. For reference, I am using Robolectric 4.6, which I believe may be the reason why I am requiring a different solution from non-instrumented tests.

The solution I came up with (to verify an item is appearing in an AutoCompleteTextView popup is:

fun testAutoCompleteTextViewEntry() {
  onView(withId(R.id.editText_search))
    .perform(typeTextIntoFocusedView("x"), showDropDown())
  onView(withText("xyz"))
   .inRoot(RootMatchers.isPlatformPopup())
   .check(matches(isDisplayed()))
}

// Somewhere else in your code
fun showDropDown(): ViewAction =
   object : ViewAction {
     override fun getDescription(): String = "Shows the dropdown menu of an AutoCompleteTextView"

     override fun getConstraints(): Matcher<View> = allOf(
       isEnabled(), isAssignableFrom(AutoCompleteTextView::class.java)
     )

     override fun perform(uiController: UiController, view: View) {
       val autoCompleteTextView = view as AutoCompleteTextView
       autoCompleteTextView.showDropDown()
       uiController.loopMainThreadUntilIdle()
     }
}

Upvotes: 2

Mr-IDE
Mr-IDE

Reputation: 7661

Following on from the answer from AStupidNoob on 28 July 2017...

To click on a specific row number of the drop-down list, you can use this:

onData(anything())
    .atPosition(2)
    .inRoot(RootMatchers.isPlatformPopup())
    .perform(click());

To click on a specific item in a specific row number of the drop-down list, you can use this:

onData(anything())
    .atPosition(2)
    .inRoot(RootMatchers.isPlatformPopup())
    .onChildView(withId(R.id.button_on_layout))
    .perform(click());

Upvotes: 3

Akbolat SSS
Akbolat SSS

Reputation: 2071

By some reasons which I don't know, AStupidNoob's solution doesn't work. So I found another one:

onView(withText("Spinner Item"))
            .inRoot(RootMatchers.isPlatformPopup())
            .perform(click());

The AutoCompleteTextView itself

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/textInputLayout2"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="12dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    app:layout_constraintEnd_toStartOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <AutoCompleteTextView
        android:id="@+id/product"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:completionThreshold="1"
        android:hint="@string/product"
        android:singleLine="true"
        android:textSize="16sp" />

</com.google.android.material.textfield.TextInputLayout>

Upvotes: 27

AStupidNoob
AStupidNoob

Reputation: 2050

I think I found a bit of a cleaner method than the accepted answer!

onData(equalTo("ITEM")).inRoot(RootMatchers.isPlatformPopup()).perform(click());

The breakdown:

  • onData(x) This will find the view rendering the data object matching x in the drop down. The data is provided by the Adaptor given to the AutoCompleteTextView, so it can be an object of any type that Adaptor provides, it probably won't be a View. You'll want to use the standard hamcrest core matchers for this (equalTo, instanceOf, etc...) rather than (withText, withId, etc...). It might be a pain to try and find what object this is and how to match it, but there isn't a neater way: with a lot of items in your adapter some of the views won't even be in the hierarchy yet, so onView can't work! onData will make sure to load the views that match your data. Checkout here (this what onData returns) and here (this loads the matching data)
  • inRoot(RootMatchers.isPlatformPopup()) So it turns out the dropdown menu is on another window than the default window your activity runs in. So we have to specify that we want to search that window. The accepted answer uses RootMatchers.withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))) which seems to match any window that is not the default one.

Anyways HTH someone else.

Upvotes: 15

user3050720
user3050720

Reputation: 553

So i finally figured it out, thanks to this previous question: Testing autocomplete textview using espresso tool

Ill just post my version of it for people who might use it in future.

    onData(instanceOf("Whatever your arrayadapter contains".class)).inRoot(RootMatchers.withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView())))).perform(ViewActions.click());

Upvotes: 1

Related Questions