Monday, 26 April 2021

Espresso - How to tap on specific item of a BottomNavigationBar

I'm trying to click on an item of my BottomNavigationBar but even if I record an Espresso test and then put it on my test it doesn't find the onView.

What record an Espresso test is giving wrote for me is :

private fun childAtPosition(
        parentMatcher: Matcher<View>, position: Int
    ): Matcher<View> {

        return object : TypeSafeMatcher<View>() {
            override fun describeTo(description: Description) {
                description.appendText("Child at position $position in parent ")
                parentMatcher.describeTo(description)
            }

            public override fun matchesSafely(view: View): Boolean {
                val parent = view.parent
                return parent is ViewGroup && parentMatcher.matches(parent)
                    && view == parent.getChildAt(position)
            }
        }
    }


    val bottomNavigationItemView = onView(
            allOf(
                withContentDescription("Home"),
                childAtPosition(
                    childAtPosition(
                        withId(R.id.navigation_bar),
                        0
                    ),
                    1
                ),
                isDisplayed()
            )
        )
        bottomNavigationItemView.perform(click())

And even if I try this, it says :

androidx.test.espresso.PerformException: Error performing 'single click' on view '(with content description text: is "Home" and Child at position 1 in parent Child at position 0 in parent with id is <package_name:id/navigation_bar> and is displayed on the screen to the user)'.

I've tried several ways, with BoundedMatcher but I couldn't get it work. What I'm missing?

fun withTitle(titleTested: String): Matcher<View?>? {
        return object : BoundedMatcher<View?, BottomNavigationItemView>(
            BottomNavigationItemView::class.java
        ) {
            private var triedMatching = false
            private var title: String? = null
            override fun describeTo(description: Description) {
                if (triedMatching) {
                    description.appendText("with title: $titleTested")
                    description.appendText("But was: " + title.toString())
                }
            }

            override fun matchesSafely(item: BottomNavigationItemView): Boolean {
                triedMatching = true
                title = item.itemData.title.toString()
                return title == titleTested
            }
        }
    }

The hierarchy of my xml is :

CoordinatorLayout(id : mainCordinator)
   RelativeLayout (no id)
      com.google.android.material.bottomnavigation.BottomNavigationView(id : navigation_bar) />
         Coordinatorlayout(id: anotherCoordinator)
           FrameLayout(id: framelayout)
           FloatActionButton(id: fab_test)
         />
   />  
/>

I'd like to know the easiest way so I can call a function passing the index of the bottomNav and click on it, or even sending as a parameter the ContentDescription/Title/Text, whatever it is.

I'm creating the items dynamically as follows :

        ArrayList<String> items...
        ....Create....
        Menu menu = binding.navigationBar.getMenu();
        menu.clear();
        for (int i = 0; i < items.size(); i++) {
            menu.add(
                0,
                items.get(i),
                i,
                bottomBarTitles.get(i));
            menu.getItem(i).setIcon(bottomBarImages.getItemIcon(items.get(i)));
            bottomMenu.add(items.get(i));

Items is a ArrayList<String> with for instance "Home, Content, Images, More" And then I have another ArrayList with the images.

Edit

I could make it work using UiDevice and UiSelector but I would like to use Espresso for this one.

val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
            device.findObject(UiSelector().text("Home")).click()


from Espresso - How to tap on specific item of a BottomNavigationBar

No comments:

Post a Comment