How to iterate over an element (node) list on Android Jetpack Compose UI Tests?
Asked Answered
T

3

8

I'm implementing some instrumented tests using the Jetpack Compose testing library. I'm not too familiar with Kotlin / Android development yet, but I have years of experience with Selenium and other testing libraries, so I'm missing some basic things and have no idea how to implement them.

What I want to do:

  1. Iterate over an element (node) list. I have this list an all items are identified by the same test tag "item". I need to click on each one of these items.

On Selenium I can easily do that:

elements = driver.find_elements("item")
elements.each do |element|
  element.click
end

But on Kotlin with the Composing Testing Framework I have no clue how to do that. The method below (responsible for returning a list of nodes) doesn't support forEach:

composeTestRule.onAllNodes(hasTestTag("item")
  1. I also want to retrieve the list size.

On Selenium the method below returns the qty of items found:

driver.find_elements("item").size 

But, again, there's nothing like that available with composing:

composeTestRule.onAllNodes(hasTestTag("item")

I've already read the official JetPack Compose Testing Tutorial, but it doesn't provide much details

Thereon answered 24/12, 2022 at 2:24 Comment(0)
P
8

To iterate:

composeTestRule.onAllNodes(hasTestTag("item")).apply {
    fetchSemanticsNodes().forEachIndexed { i, _ ->
        get(i).performClick()
    }
}

To check size:

composeTestRule.onAllNodes(hasTestTag("item")).fetchSemanticsNodes().size == 1
Pantywaist answered 2/1, 2023 at 12:44 Comment(1)
Thanks for the iteration example, it was the only way to make it work for me!Mun
M
1

I'm not sure how you'd go about iterating over a SemanticsNodeInteractionCollection. I'm also uncertain of why you'd want to do that. That said, in a testing scenario you'd likely have an expected count of items in a collection. Therefore, you can create a range and get the SemanticsNodeInteraction for each element that .OnAllNodes() returns.

Example where I expect there to be 10 ui elements returned:

        val nodes = composeTestRule.onAllNodes(hasTestTag("item"))
        for (index in 0..10) {
            val node = nodes[index]
            // node.assert whatever you want here.
        }

Asserting the count equals something can also be done through:

composeTestRule.onAllNodes(hasTestTag("item")).assertCountEquals(10)

If you just want to get the total count and not assert it. I'd argue there might be something wrong with the tests themselves. I'd expect your test to be a controlled environment where you know exactly how many items should be shown on the screen at any given time.

Let me know if this helps, otherwise please elaborate on your exact scenario.

Metagalaxy answered 24/12, 2022 at 11:39 Comment(0)
M
0

Following Kaan Sariveli example, if you want to iterate over all the clickable nodes and perform click on them, this is the only way that worked for me:

composeTestRule.onAllNodesWithTag("item")
    .filter(hasClickAction())
    .apply {
        fetchSemanticsNodes().forEachIndexed { i, _ ->
            get(i).performSemanticsAction(SemanticsActions.OnClick)
        }
    }
Mun answered 23/8, 2023 at 22:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.