使用 Espresso 在 ViewPager 中查找视图(AmbiguousViewMatcherException)

Finding views in a ViewPager using Espresso (AmbiguousViewMatcherException)

我有一个 ViewPager,一次只在屏幕上显示一个片段。此片段有一个 recyclerView,其中填充了由一个图像和两个 textView 组成的列表项。我需要 select 项目并根据显示的文本执行点击。

我的 viewPage 有 ID pager,recyclerView 是 listview,我正在使用 cardView 小部件,它有一个名为 cardContainer 的相对布局,它有一个 textView [=16] =] 我感兴趣的。

Espresso 似乎只能识别 pager,但它无法在视图层次结构中找到任何其他 ID。我如何访问 nickName 或基本上 viewPager 或片段中的任何其他视图?

我尝试了以下方法:

        ViewInteraction listviewInteraction = onView (allOf(withId(R.id.pager)));
    listviewInteraction.check(matches(hasDescendant(withId(R.id.listview))));

我收到以下错误,因为寻呼机没有任何子节点

    Expected: has descendant: with id: 2131689666
Got: "ViewPager{id=2131689659, res-name=pager, visibility=VISIBLE, width=1080, height=1533, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=144.0, child-count=0}"

我也尝试了一些与发布的方法类似的不同方法 here 但 Espresso 找不到 listviewnickname.

如何找到视图 nickName

更新:

我还有 运行 几个测试,当 Espresso 运行 进行测试时,viewPager 似乎从不加载片段。我试过使用 Thread.sleep() 等待一段时间但没有运气。我看到 listView 只填充了一会儿,然后寻呼机变为空白并且测试失败,因为它找不到任何其他视图。知道是什么原因造成的吗?

更新 2:

分页器现在正常加载,但 Espresso 无法识别 listview 或 cardContainer,但由于 AmbiguousViewMatcherException 而只能识别分页器。 viewPager 中有四个片段,但屏幕上只显示一个片段。我的代码如下:

ViewInteraction listviewInteraction = onView (allOf(withId(R.id.pager)));
    listviewInteraction.check(matches(isDisplayed()));
    onView(allOf(withId(R.id.listview), isDisplayed())).check(matches(isDisplayed()));

视图层次结构中有两个匹配项。如果我不在 viewMatcher 中使用 isDisplayed() 方法,那么我会得到四个片段的四个匹配项。我该如何解决?

屏幕外显然有一个列表视图,尽管它不可​​见。匹配器 isDisplayed() 还考虑了屏幕外的视图。使用 isCompletelyDisplayed() 修复了 AmbiguousViewMatcherException.

如果有人对选择 TabByText 下面的机制感兴趣

/**
 * Select Tab by [tabName] if it's available. Otherwise Throw PerformException
 */
fun selectTabByText(tabName: String, contains: Boolean = false, ignoreCase: Boolean = false): ViewAction {
    return object : ViewAction {
        override fun getDescription() = "With tab name $tabName"

        override fun getConstraints() = Matchers.allOf(isDisplayed(), ViewMatchers.isAssignableFrom(TabLayout::class.java))

        override fun perform(uiController: UiController, view: View) {
            val tabLayout = view as TabLayout
            val tabCount = tabLayout.tabCount
            for (tabIndex in 0 until tabCount) {
                /**
                 * Get the text of each available tab and if it's the same as [tabName]
                 * then select it
                 */
                val tabAtIndex: TabLayout.Tab = tabLayout.getTabAt(tabIndex)
                    ?: throw PerformException.Builder()
                        .withCause(Throwable("Tab at Index $tabIndex failed to be resolved to a Tab Object"))
                        .build()
                val tabText = tabAtIndex.text.toString()
                if (tabText.compare(tabName, ignoreCase, contains)) {
                    tabAtIndex.select()
                    return
                }
            }
            throw PerformException.Builder()
                .withCause(Throwable("Tab with name: $tabName with params: contains = $contains and ignoreCase = $ignoreCase is not found"))
                .build()
        }
    }
}

/**
 * Returns true if [contains] is true and this String contains the specified [other] String as a substring, optionally ignoring character case.
 * Returns true if [contains] is false and this string is equal to other, optionally ignoring character case.
 * @param ignoreCase `true` to ignore character case when comparing strings. By default `false`.
 */
fun String.compare(other: String, ignoreCase: Boolean = false, contains: Boolean = false): Boolean =
    if (contains) {
        this.contains(other, ignoreCase = ignoreCase)
    } else