androidautomated-testsandroid-uiautomatormacrobenchmark

Android UIAutomator: How to wait for any of multiple conditions?


As a step in creating baseline profiles for my app, I need to wait for my feed to render. The problem is that I do not know the exact tag to wait for since the feed is dynamic and the tag might not render at all.

So basically I want to wait for any of the possible tags to be there. As soon as the first one appears, the code should return true. I do not know how to do this. This is what I am doing at the moment:

fun MacrobenchmarkScope.waitForDashboardContent() {
    device.wait(Until.hasObject(By.res("dashboard_feed")), 10_000)
    val lazyColumn = device.findObject(By.res("dashboard_feed"))
    lazyColumn.wait(Until.hasObject(By.res("dashboard_section_title")), 2_000)
}

ChatGPT suggested something that would be great, except this method doesn't exist:

lazyColumn.wait(Until.hasObject(By.any(By.res("dashboard_section_title"),By.res("another_section_title"))),2_000)

When I confronted it that By.any doesn't exist, it gave me this suggestion:

val lazyColumn = device.findObject(By.res("dashboard_feed"))
val startTime = System.currentTimeMillis()
val timeout = 2000

while (System.currentTimeMillis() - startTime < timeout) {
    if (lazyColumn.hasObject(By.res("dashboard_section_title")) ||
        lazyColumn.hasObject(By.res("another_section_title"))) {
        // One of the elements was found within the timeout
        break
    }
    // Small delay to prevent tight looping
    Thread.sleep(100)
}

Is there a better solution?


Solution

  • I figured out the solution. I ended up using a regex to match different possible elements, since By.res() function can take a Pattern as argument. Here is the complete function:

    fun MacrobenchmarkScope.waitForDashboardContent() {
        device.wait(Until.hasObject(By.res("dashboard")), 10_000)
        val lazyColumn = device.findObject(By.res("dashboard"))
        val listOfElements = listOf("banner", "title", "survey", "claim")
        val regex = listOfElements.joinToString(separator = "|")
        val patternToMatch = Pattern.compile(regex)
        lazyColumn.wait(Until.hasObject(By.res(patternToMatch)), 4_000)
    }
    

    This way the test will complete successfully if any of those elements is found on the screen.