Compose Android Test Lazy Column Not Detect All The Children
G

4

8

I have a LazyColumn inside a Composable, I want to check every item in that LazyColumn is exist.

This is my composable: (Note: Actually in my real case the each item has different component, I just make it similar for simplify the question)

@Composable
fun HomeScreen(){
    LazyColumn(){
        item {
            HomeBanner()
            Text("Test1",Modifier.testTag("tag1"))
        }
        item {
            HomeBanner()
            Text("Test2",Modifier.testTag("tag2"))
        }
        item {
            HomeBanner()
            Text("Test3",Modifier.testTag("tag3"))
        }
        item {
            HomeBanner()
            Text("Test4",Modifier.testTag("tag4"))
        }
        item {
            HomeBanner()
            Text("Test5",Modifier.testTag("tag5"))
        }
        item {
            HomeBanner()
            Text("Test6",Modifier.testTag("tag6"))
        }

    }
}

And this is what it's looks like:

enter image description here

This is my test class:


@ExperimentalCoroutinesApi
@ExperimentalMaterialApi
@ExperimentalPagerApi
@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class HomeScreenTest {
    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @ExperimentalMaterialApi
    @get:Rule(order = 1)
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Inject
    lateinit var mainRepository: MainRepository

    @Before
    fun setup() {
        hiltRule.inject()
    }

    @Test
    fun property_list_is_displayed() = runTest {
        composeTestRule.onRoot().printToLog("GALIH")
        composeTestRule.onNodeWithTag("tag1").assertExists()
        composeTestRule.onNodeWithTag("tag2").assertExists()
        composeTestRule.onNodeWithTag("tag3").assertExists()
        composeTestRule.onNodeWithTag("tag4").assertExists()
        composeTestRule.onNodeWithTag("tag5").assertExists()
    }
}

And it throws an error when assert Exist the tag5:

java.lang.AssertionError: Failed: assertExists.
Reason: Expected exactly '1' node but could not find any node that satisfies: (TestTag = 'tag5')

When I see the log, it shows that there is no tag5 in the view hierarchy

printToLog:
                                                                                                    Printing with useUnmergedTree = 'false'
                                                                                                    Node #1 at (l=0.0, t=58.0, r=720.0, b=1510.0)px
                                                                                                     |-Node #6 at (l=0.0, t=58.0, r=720.0, b=1510.0)px
                                                                                                     | IsContainer = 'true'
                                                                                                     |  |-Node #45 at (l=0.0, t=163.0, r=720.0, b=1510.0)px
                                                                                                     |  | VerticalScrollAxisRange = 'ScrollAxisRange(value=0.0, maxValue=6.0, reverseScrolling=false)'
                                                                                                     |  | CollectionInfo = 'androidx.compose.ui.semantics.CollectionInfo@aa9f76d'
                                                                                                     |  | Actions = [IndexForKey, ScrollBy, ScrollToIndex]
                                                                                                     |  |  |-Node #48 at (l=45.0, t=208.0, r=675.0, b=583.0)px
                                                                                                     |  |  | ContentDescription = '[]'
                                                                                                     |  |  | Role = 'Image'
                                                                                                     |  |  |-Node #49 at (l=75.0, t=455.0, r=645.0, b=553.0)px
                                                                                                     |  |  | Text = '[Temukan Hunian Impian Anda Hanya Disini!]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #50 at (l=45.0, t=583.0, r=120.0, b=626.0)px, Tag: 'tag1'
                                                                                                     |  |  | Text = '[Test1]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #53 at (l=45.0, t=626.0, r=675.0, b=1001.0)px
                                                                                                     |  |  | ContentDescription = '[]'
                                                                                                     |  |  | Role = 'Image'
                                                                                                     |  |  |-Node #54 at (l=75.0, t=873.0, r=645.0, b=971.0)px
                                                                                                     |  |  | Text = '[Temukan Hunian Impian Anda Hanya Disini!]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #55 at (l=45.0, t=1001.0, r=124.0, b=1044.0)px, Tag: 'tag2'
                                                                                                     |  |  | Text = '[Test2]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #58 at (l=45.0, t=1044.0, r=675.0, b=1419.0)px
                                                                                                     |  |  | ContentDescription = '[]'
                                                                                                     |  |  | Role = 'Image'
                                                                                                     |  |  |-Node #59 at (l=75.0, t=1291.0, r=645.0, b=1389.0)px
                                                                                                     |  |  | Text = '[Temukan Hunian Impian Anda Hanya Disini!]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #60 at (l=45.0, t=1419.0, r=125.0, b=1462.0)px, Tag: 'tag3'
                                                                                                     |  |  | Text = '[Test3]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #63 at (l=45.0, t=1462.0, r=675.0, b=1837.0)px
                                                                                                     |  |  | ContentDescription = '[]'
                                                                                                     |  |  | Role = 'Image'
                                                                                                     |  |  |-Node #64 at (l=75.0, t=1709.0, r=645.0, b=1807.0)px
                                                                                                     |  |  | Text = '[Temukan Hunian Impian Anda Hanya Disini!]'
                                                                                                     |  |  | Actions = [GetTextLayoutResult]
                                                                                                     |  |  |-Node #65 at (l=45.0, t=1837.0, r=125.0, b=1880.0)px, Tag: 'tag4'
                                                                                                     |  |    Text = '[Test4]'
                                                                                                     |  |    Actions = [GetTextLayoutResult]
                                                                                                     |  |-Node #30 at (l=0.0, t=58.0, r=720.0, b=163.0)px
                                                                                                     |    IsContainer = 'true'
                                                                                                     |     |-Node #33 at (l=31.0, t=89.0, r=76.0, b=134.0)px
                                                                                                     |     | Role = 'Button'
                                                                                                     |     | Focused = 'false'
                                                                                                     |     | ContentDescription = '[]'
                                                                                                     |     | Actions = [OnClick, RequestFocus]
                                                                                                     |     | MergeDescendants = 'true'
                                                                                                     |     |-Node #36 at (l=136.0, t=73.0, r=712.0, b=148.0)px
                                                                                                     |       ContentDescription = '[]'
                                                                                                     |       Role = 'Image'
                                                                                                     |-Node #9 at (l=-720.0, t=58.0, r=-105.0, b=1510.0)px
                                                                                                       PaneTitle = 'Navigation menu'
                                                                                                       IsContainer = 'true'
                                                                                                        |-Node #13 at (l=-720.0, t=94.0, r=-105.0, b=180.0)px
                                                                                                        | Focused = 'false'
                                                                                                        | Text = '[Home]'
                                                                                                        | Actions = [OnClick, RequestFocus, GetTextLayoutResult]
                                                                                                        | MergeDescendants = 'true'
                                                                                                        |-Node #16 at (l=-720.0, t=180.0, r=-105.0, b=266.0)px
                                                                                                        | Focused = 'false'
                                                                                                        | Text = '[Properti]'
                                                                                                        | Actions = [OnClick, RequestFocus, GetTextLayoutResult]
                                                                                                        | MergeDescendants = 'true'
                                                                                                        |-Node #19 at (l=-720.0, t=266.0, r=-105.0, b=352.0)px
                                                                                                        | Focused = 'false'
                                                                                                        | Text = '[Project]'
                                                                                                        | Actions = [OnClick, RequestFocus, GetTextLayoutResult]
                                                                                                        | MergeDescendants = 'true'
                                                                                                        |-Node #22 at (l=-720.0, t=352.0, r=-105.0, b=438.0)px
                                                                                                        | Focused = 'false'
                                                                                                        | Text = '[Agent]'
                                                                                                        | Actions = [OnClick, RequestFocus, GetTextLayoutResult]
                                                                                                        | MergeDescendants = 'true'
                                                                                                        |-Node #25 at (l=-720.0, t=438.0, r=-105.0, b=524.0)px
                                                                                                          Focused = 'false'
                                                                                                          Text = '[Developer]'
                                                                                                          Actions = [OnClick, RequestFocus, GetTextLayoutResult]
                                                                                                          MergeDescendants = 'true'

How I tested the rest of the children on my lazy column?

Gamber answered 23/4, 2023 at 13:20 Comment(0)
I
10

You could use either performScrollToIndex to scroll to the index of the items that are not in the view tree:

composeTestRule.onNodeWithTag("tag of LazyColumn")
    .performScrollToIndex(position) // position of the item, seems to be 15 in your sample

Or, use performScrollToNode to scroll to a node with a text:

composeTestRule.onNodeWithTag("tag of LazyColumn")
    .performScrollToNode(hasText("tag5"))

Then the assertion should work:

composeTestRule.onNodeWithTag("tag5").assertExists()
Infuscate answered 26/5, 2023 at 11:1 Comment(3)
how do your measure that the position of the item in my case is 15?Gamber
@Gamber If you scroll to the 15th item and the corresponding content assertion succeeds, then it pretty much proves that the item position is 15.Gross
This doesn't work for lazyverticalgrid, it says that lazyverticalgrid doesn't support scrolling.Wingo
L
1

You can use performScrollTo()

https://developer.android.com/reference/kotlin/androidx/compose/ui/test/package-summary#(androidx.compose.ui.test.SemanticsNodeInteraction).performScrollTo()

listOf("tag1", "tag2", "tag3", "tag4", "tag5").forEach { tag ->
   composeTestRule.onNodeWithTag(tag).performScrollTo().assertIsDisplayed()
}
Lorgnon answered 27/4, 2023 at 7:59 Comment(0)
P
1

A similar scenario I resolved with below code.

@Test
fun testProductListState() = runBlocking{
    val list = testProducts()

    composeTestRule.setContent {
            ProductScreen(products = list)
        }
    list.forEach(){ product ->
        val cardTag = product.productCode
        val cardNode = onNodeWithTag(cardTag)
        onNodeWithTag("MyLazyColumnTag", useUnmergedTree = true)
          .performScrollToNode(hasTestTag(cardTag))//test tag for list item
        delay(300L)
        cardNode.assertIsDisplayed()
}
Plagal answered 25/8, 2023 at 13:26 Comment(1)
This answer worked, but why do we have to do this? performScrollTo technically is supposed to use the nearest scrollable parent as I'm not sure why this workaround is needed.Realistic
A
0

I had a similar problem, until now, the only way that I found to solve went using performTouchInput{ swipeUp() } to scroll up and then made the component visible to assert it.

In your case, you maybe will be need set tag for your lazycolumn and after perform a swipeup() you may check then final childern at lazycolumn, looks like this:

 @Test
    fun property_list_is_displayed() = runTest {
        composeTestRule.onRoot().printToLog("GALIH")
        composeTestRule.onNodeWithTag("tag1").assertExists()
        composeTestRule.onNodeWithTag("tag2").assertExists()
        composeTestRule.onNodeWithTag("tag3").assertExists()
        composeTestRule.onNodeWithTag("tag4").assertExists()
        composeTestRule.onNodeWithTag("lazycolumn")
            .performTouchInput{ swipeUp() }
            .onChildren()
            .onLast()
            .assertTextContains("Test5")
    }
Antimicrobial answered 24/4, 2023 at 0:41 Comment(2)
the problem is when use swipeUp is not scrolling the lazyColumn till the last child, If i have 10 child and swipe once, in the view hierarcy the last child is 8, so I have to swipe twice to detect the rest of childrenGamber
Sorry for delay! Yes, it's really bad to do, but the answer of @Kaan Sariveli its very good, because you can do this way: rule.onNodeWithTag("lazycolumn") .performScrollToNode(hasAnySibling(hasTestTag("tag1")) .performScrollToNode(hasAnySibling(hasTestTag("tag2"))Antimicrobial

© 2022 - 2024 — McMap. All rights reserved.