3

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?

galihif
  • 310
  • 1
  • 8

4 Answers4

3

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()
Gustavo Pagani
  • 6,583
  • 5
  • 40
  • 71
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")
    }
  • 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 children – galihif Apr 25 '23 at 08:30
  • 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")) – Luiz Tadeu May 01 '23 at 00:38
0

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()
}
0

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()
}
subair_a
  • 1,028
  • 2
  • 14
  • 19