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.
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()
I would think using withID would for you, I know espresso recorded tests are flaky and it's best to write your own code.
onView(withId(R.id.home).perform(click())
I'm not sure what IDs you've assigned to navigation items, so I used home.
If the multiple views have the same ID you can use.
onView(withId(R.id.home), withText("Home")).performClick()
If you use withText() by itself it will try and perform the click action on all Views that have the word "Home".
Can you try this one:
onView( allOf( withText("Home), isDescendantOfA(withId(R.id.navigation_bar)) ).perform( click() )
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With