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()
Can you try this one:
basically we are looking for a view with text "Home" which also happens to be descendant of a view with id of your bottom bar.