Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait till a view has gone in Esspresso tests

I have a TextView that shows a "loading" string... and I need to wait till this view is gone ... I don't have a handle on the Asynctask because this method is running in a IntentService and sends a broadcast when the loading is finished.

Any idea about how to wait in an Espresso test for a change in a view's status? I'll need the same with some strings that will change and need to wait for that... I supposed it's the same case ...

Thanks for the help. There are not many examples or FAQs on the net.

like image 579
jfcogato Avatar asked Mar 12 '14 16:03

jfcogato


2 Answers

This has been answered here.

You can handle this case by registering an IdlingResource for your web service with Espresso. Take a look at this write-up.

Most likely, you'll want to use CountingIdlingResource (which uses a simple counter to track when something is idle). This sample test demonstrates how this can be done.

like image 77
ValeraZakharov Avatar answered Sep 29 '22 18:09

ValeraZakharov


Preamble

You can define a ViewAction that loops the main thread every 50 milliseconds (or a different time of your choosing) until either the visibility of the View in question changes to View.GONE or a maximum amount of time elapses.

Step 1

Define the ViewAction as follows:

/**
 * A [ViewAction] that waits up to [timeout] milliseconds for a [View]'s visibility value to change to [View.GONE].
 */
class WaitUntilGoneAction(private val timeout: Long) : ViewAction {

    override fun getConstraints(): Matcher<View> {
        return any(View::class.java)
    }

    override fun getDescription(): String {
        return "wait up to $timeout milliseconds for the view to be gone"
    }

    override fun perform(uiController: UiController, view: View) {

        val endTime = System.currentTimeMillis() + timeout

        do {
            if (view.visibility == View.GONE) return
            uiController.loopMainThreadForAtLeast(50)
        } while (System.currentTimeMillis() < endTime)

        throw PerformException.Builder()
            .withActionDescription(description)
            .withCause(TimeoutException("Waited $timeout milliseconds"))
            .withViewDescription(HumanReadables.describe(view))
            .build()
    }
}
Step 2

Define a function that creates an instance of this ViewAction when called, as follows:

/**
 * @return a [WaitUntilGoneAction] instance created with the given [timeout] parameter.
 */
fun waitUntilGone(timeout: Long): ViewAction {
    return WaitUntilGoneAction(timeout)
}
Step 3

Call on this ViewAction in your test method as follows:

onView(withId(R.id.loadingTextView)).perform(waitUntilGone(3000L))
Next steps

You can take this concept and similarly create a WaitForTextAction class that waits until a TextView's text changes to a certain value. In this case, however, you'll probably want to change the Matcher returned by the getConstraints() function from any(View::class.java) to any(TextView::class.java).

like image 25
Adil Hussain Avatar answered Sep 29 '22 18:09

Adil Hussain