26

I essentially have a custom IdlingResource that takes a View a constructor argument. I can't find anywhere that really talks about how to implement it.

I'm trying to use this answer: https://stackoverflow.com/a/32763454/1193321

As you can see, it takes a ViewPager, but when I'm registering the IdlingResource in my test class, I'm not sure how I can get my view.

I've tried findViewById() and I've tried getting the currently running activity and then calling findViewById() on that, with no luck.

Anyone know what to do in this scenario?

shizhen
  • 12,251
  • 9
  • 52
  • 88
EGHDK
  • 17,818
  • 45
  • 129
  • 204

4 Answers4

35

Figured it out. To get the view to pass into an idling resource, all you have to do is take the member variable of your ActivityTestRule

For example:

@Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(
        MainActivity.class);

and then just call getActivity().findViewById(R.id.viewId)

So the end result is:

activityTestRule.getActivity().findViewById(R.id.viewId);
EGHDK
  • 17,818
  • 45
  • 129
  • 204
15

The accepted answer works as long as a test is running in the same activity. However, if the test navigates to another activity activityTestRule.getActivity() will return the wrong activity (the first one). To address this, one can create a helper method returning an actual activity:

public Activity getCurrentActivity() {
    final Activity[] currentActivity = new Activity[1];
    InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
        @Override
        public void run() {
            Collection<Activity> allActivities = ActivityLifecycleMonitorRegistry.getInstance()
                    .getActivitiesInStage(Stage.RESUMED);
            if (!allActivities.isEmpty()) {
                currentActivity[0] = allActivities.iterator().next();
            }
        }
    });
    return currentActivity[0];
}

And then it could be used as the following:

Activity currentActivity = getCurrentActivity();
if (currentActivity != null) {
    currentActivity.findViewById(R.id.viewId);
}
Anatolii
  • 14,139
  • 4
  • 35
  • 65
9

If you are using ActivityScenarioRule from androidx.test.ext.junit.rules (since ActivityTestRule "will be deprecated and eventually removed from library in the future"), you can get your Activity instance and call findViewById method:

import androidx.test.ext.junit.rules.activityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4

@RunWith(AndroidJUnit4::class) {

    @get: Rule
    var testRule = activityScenarioRule<MainActivity>()

    @Test
    fun mainTestCase() {
        testRule.scenario.onActivity { activity ->
            val view = activity.findViewById<YourView>(R.id.view)
        }
    }
}

1

I haven't already used IdilingResources in Espresso, but did you saw these articles:

Also please check official Android Docs: Idling Resources (reference)

To answer your question,

Here's an exmple taken from a link above:

Starting with a context, the root view of the associated activity can be had by

View rootView = ((Activity)_context).Window.DecorView.FindViewById(Android.Resource.Id.Content);

In Raw Android it'd look something like:

View rootView = ((Activity)mContext).getWindow().getDecorView().findViewById(android.R.id.content)

Then simply call the findViewById on this

View v = rootView.findViewById(R.id.your_view_id);

This might be also useful: How to call getResources() from a class which has no context?

Hope it help

Community
  • 1
  • 1
piotrek1543
  • 19,130
  • 7
  • 81
  • 94
  • Thanks for the links and code snippets. I've read through those links before I posted the question. Chiukis blog posts are awesome. But your answer seems awfully "hacky" to me. There has to be a way to get a view object directly from an espresso test no? – EGHDK Jan 13 '16 at 11:34