How to make espresso wait for activity that is triggered by a firebase call?

Issue

I have a LoginActivity, which uses firebase as the back-end. When I have successfully signed in, my MainActivity shows up successfully.

How do I write an Espresso test for this activity change?

The ordinary way, that Espresso keeps track of the current activity itself does only seems to work on activities that does not need to wait for firebase. When using it when using firebase auth, I get this error message:

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: (my application package):id/button2

(button2 is the id of a button in the new activity, but this happens with whatever view I’m trying to reach in the new activity)

I’ve also tried to use ActivityMonitor and similar methods. They do not seem to fetch any activity change at all.

Thread.sleep() gives the impression to do exactly the opposite of what I want to do: It seems to pause the application, not the test itself.

I’m aware that I should not test the functionality of firebase itself, but my application relies heavily on the user being signed in, and I would late on like to write other tests which tests the GUI and functionality for users that have signed in.

How do I write an correct espresso test for an activity change when using firebaseauth to check if I should trigger the activity?

Solution

You need to use the IdlingResource class. Espresso does not have a way to tell when your UI is waiting on an asynchronous network call such as Firebase. IdlingResource was created for this exact purpose. Here’s one way to solve your problem.

  1. In your code have something that keeps track of when you waiting for a network call. Maybe a boolean called isInProgress.
  2. create an IdlingResource class in the same folder as your test, something like this:

Example:

import android.support.test.espresso.IdlingResource
import com.myexample.MainActivity


class LoginIdlingResource constructor(
        private val mainActivity: MainActivity
) : IdlingResource{

    private var resourceCallback: IdlingResource.ResourceCallback?  null

    override fun getName(): String {
        return LoginIdlingResource::class.java.name
    }

    override fun isIdleNow(): Boolean {
        return !mainActivity.isInProgress() // <----- Important part
    }

    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
        this.resourceCallback  callback
    }
}
  1. Register the IdlingResource class in your tests @Before function like this:

Example:

@get:Rule
val mActivityTestRule: ActivityTestRule<MainActivity>  ActivityTestRule(MainActivity::class.java)

@Before
fun init() { IdlingRegistry.getInstance()
    .register(RegisterIdlingResource(mActivityTestRule.activity))
}

Now Espresso will wait whenever your Boolean says isInProgress.

Answered By – szaske

Leave a Comment