Android Studio 自Compose BOM 2023.08.00以来,插装测试失败,因为惰性列表更改似乎在层次结构中留下了旧节点

tvokkenx  于 2023-10-23  发布在  Android
关注(0)|答案(1)|浏览(175)

Jetpack Compose版本:编写BOM 2023.08.00
使用的Jetpack合成组件:基础、材质、动画、livedata、ui工具、viewmodel
Kotlin版本:1.9.10
再现步骤或再现代码样本:

  • 当向lazyColumn添加一个项并将列中底部的项推到更低位置时,项节点将被复制。这使得我的 Jmeter 化测试失败,因为有多个节点具有相同的测试标记。这在BOM 2023.08.00编写前未发生
  • 请查看附件截图。当惰性列表项更改时,节点在层次结构中保持持久性。如果您查看这两个截图,其中一个显示了按钮所在的真实的节点,我们可以看到节点上的参数。另一个屏幕截图显示了一个虚拟节点,按钮曾经在那里。它没有参数。
    是否有人经历过这种情况,如果是这样,是否有解决方案仅在编写 Jmeter 化测试中针对可见节点,而不会获得模糊的节点异常?

下面是我的lazyColumn实现的一些示例代码:

LazyColumn(
        modifier = Modifier.testTag(COMMUTE_ITEM_LIST),
        state = state
    ) {
        item { Spacer(modifier= Modifier.height(topPaddingDp)) }
        items(itemViews.size, key = { itemViews[it].uniqueId }) { index ->
            AnimateItemPlacements {
                CommuteItemRow(
                    modifier = Modifier,
                    itemViews = itemViews,
                    index = index,
                    onRemoveItemAtIndex = onRemoveItemAtIndex,
                    onEditItemAtIndex = onEditItemAtIndex,
                    onItemMoved = onItemMoved
                )
            }
        }

        item {
            AddItemButton(
                modifier = Modifier,
                index = itemViews.size,
                onAddItemAtIndex = onAddItemAtIndex
            )
        }
        item {
            Spacer(Modifier.height(bottomPaddingDp))
        }
    }

问题跟踪器链接:https://issuetracker.google.com/issues/299304333

k4emjkb1

k4emjkb11#

在浏览了https://issuetracker.google.com/issues/187188981之后,有一个解决方案最终对我有效。
问题是,一些节点仍然缓存在懒惰列表中,并且当测试试图通过这样的调用来挑选特定节点时,现在会抛出异常:

composeTestRule.onNodeWithTag("testTag")

在此期间(直到Compose团队修复此问题)的解决方案是使用这些扩展函数,请参阅上述链接的帖子#12中的海报:

/** A patched version of [ComposeTestRule.onNode] that filters out cached views from lazy views. */
fun ComposeTestRule.onNodePatched(matcher: SemanticsMatcher) =
    onNode(matcher and isNotCached())

/** A patched version of [ComposeTestRule.onNodeWithText] that filters out cached views from lazy views. */
fun ComposeTestRule.onNodeWithTextPatched(text: String, substring: Boolean = false, ignoreCase: Boolean = false, useUnmergedTree: Boolean = false) =
    onAllNodesWithText(text = text, substring = substring, ignoreCase = ignoreCase, useUnmergedTree = useUnmergedTree)
        .filterToOneNotCached()

/** A patched version of [ComposeTestRule.onNodeWithTag] that filters out cached views from lazy views. */
fun ComposeTestRule.onNodeWithTagPatched(testTag: String, useUnmergedTree: Boolean = false) =
    onAllNodesWithTag(testTag = testTag, useUnmergedTree = useUnmergedTree)
        .filterToOneNotCached()

/** A patched version of [ComposeTestRule.onNodeWithContentDescription] that filters out cached views from lazy views. */
fun ComposeTestRule.onNodeWithContentDescriptionPatched(label: String) =
    onAllNodesWithContentDescription(label = label)
        .filterToOneNotCached()

/** A patched version of [ComposeTestRule.onAllNodesWithText] that filters out cached views from lazy views. */
fun ComposeTestRule.onAllNodesWithTextPatched(text: String) =
    onAllNodesWithText(text = text)
        .filterOutCached()

/** A patched version of [ComposeTestRule.onAllNodesWithContentDescription] that filters out cached views from lazy views. */
fun ComposeTestRule.onAllNodesWithContentDescriptionPatched(label: String) =
    onAllNodesWithContentDescription(label = label)
        .filterOutCached()

/** Filters out cached views from lazy views and expects 1 or 0 results. */
fun SemanticsNodeInteractionCollection.filterToOneNotCached() =
    filterToOne(isNotCached())

/** Filters out cached views from lazy views and expects 0 or more results. */
fun SemanticsNodeInteractionCollection.filterOutCached() =
    filter(isNotCached())

/**
 * Matches against only nodes that are not "cached" by lazy lists. This allows us to filter out
 * nodes that do not appear in the UI but are reported by Compose's testing framework. These cached
 * nodes cause issues because they will cause assertIsDisplayed to fail due to 2 nodes with the same
 * values are reportedly displayed, but one is displayed and the other is cached. Cached nodes also
 * cause assertDoesNotExist to fail because the cached node that does not exist on the UI does exist
 * according to the test framework.
 *
 * This matcher is used in the methods above to globally filter out these very unexpected nodes.
 * We hope Compose stops reporting these cached nodes in a future update and we can remove this patch.
 *
 * https://issuetracker.google.com/issues/187188981
 */
fun isNotCached() = SemanticsMatcher("isNotCached") { node -> node.layoutInfo.isPlaced }

相关问题