1

I am displaying a TabLayout and connecting it to a ViewPager2 object (by means of the TabLayoutMediator class). The TabLayout has a tabMode of scrollable and contains more tabs than can fit in the screen at once. I want to assert that a certain one of the tabs is visible and selected when my activity or fragment is rendered. How do I do this?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147

2 Answers2

1

Thanks to Aaron's answer, I've defined withTabText(text:) and isSelectedTab() functions and my test's are now reading more fluently, as follows:

onView(withTabText("SomeText")).check(matches(isCompletelyDisplayed()))
onView(withTabText("SomeText")).check(matches(isSelectedTab()))

The isSelectedTab() function is implemented as follows:

/**
 * @return A matcher that matches a [TabLayout.TabView] which is in the selected state.
 */
fun isSelectedTab(): Matcher<View> =
    object : BoundedMatcher<View, TabLayout.TabView>(TabLayout.TabView::class.java) {

        override fun describeTo(description: Description) {
            description.appendText("TabView is selected")
        }

        override fun matchesSafely(tabView: TabLayout.TabView): Boolean {
            return tabView.tab?.isSelected == true
        }
    }

The withTabText(text:) function is implemented as follows:

/**
 * @param text The text to match on.
 * @return A matcher that matches a [TabLayout.TabView] which has the given text.
 */
fun withTabText(text: String): Matcher<View> =
    object : BoundedMatcher<View, TabLayout.TabView>(TabLayout.TabView::class.java) {

        override fun describeTo(description: Description) {
            description.appendText("TabView with text $text")
        }

        override fun matchesSafely(tabView: TabLayout.TabView): Boolean {
            return text == tabView.tab?.text
        }
    }

I've added both of these functions to my collection of custom view matchers in the android-test-utils GitHub repo.

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
1

You can create a custom Matcher for the tabs:

fun withTab(title: String) = withTab(equalTo(title))

fun withTab(title: Matcher<String>): Matcher<View> {
    return object : BoundedMatcher<View, TabView>(TabView::class.java) {
        override fun describeTo(description: Description) {
            description.appendText("with tab: ")
            title.describeTo(description)
        }

        override fun matchesSafely(item: TabView): Boolean {
            return title.matches(item.tab?.text)
        }
    }
}

Then to find if a tab is currently showing, you can conveniently do it with:

onView(withTab("tab text")).check(matches(isCompletelyDisplayed()))

If you want to assert if a tab is currently selected, you can either adjust matchesSafely to work with item.tab?.isSelected, or simply create a new matcher.

However if you have more than one TabLayout on the screen, then you may need to composite your matcher with isDescendantOfA or withParent.

Aaron
  • 3,764
  • 2
  • 8
  • 25