CHINTAN PATEL
CHINTAN PATEL

Reputation: 23

any method to wait until invisible progressbar in espresso test?

Eg. I have created two activities and second activities contain recycler item list and progress bar. until finish API call we are waiting for a response and shows progress bar

Upvotes: 2

Views: 1312

Answers (3)

JCarlosR
JCarlosR

Reputation: 1662

This is just an adapted version of jeprubio's solution.

/**
 * Wait until the element is accessible and not shown.
 * @param millis The maximum timeout to wait for.
 */
fun waitUntilNotShown(millis: Long): ViewAction {
    return object : ViewAction {
        override fun getConstraints(): Matcher<View> {
            return any(View::class.java)
        }

        override fun getDescription(): String {
            return "Wait for a specific view to be hidden, for a max of $millis ms."
        }

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

            val startTime = System.currentTimeMillis()
            val endTime = startTime + millis

            do {
                if (!view.isShown) {
                    return
                }
                uiController.loopMainThreadForAtLeast(100)
            } while (System.currentTimeMillis() < endTime)

            throw PerformException.Builder()
                .withActionDescription(this.description)
                .withViewDescription(HumanReadables.describe(view))
                .withCause(TimeoutException())
                .build()
        }
    }
}

Then we can use this way:

onView(withId(R.id.welcome_progress_bar))
  .perform(waitUntilNotShown(3_000))

I made this change since I was getting errors when using onView(isRoot()).

Upvotes: 0

Myralyn Garcia
Myralyn Garcia

Reputation: 21

//I use this simple code (no IdlingResource os custom matcher). Where viewId is the view you want to verify once ProgressBar is gone

fun viewIsDisplayedAfterProgressDialogIsGone(viewId: Int){
    onView(withId(viewId))
        .inRoot(not(RootMatchers.isDialog()))
        .check(matches(isDisplayed()))
}

Upvotes: 2

jeprubio
jeprubio

Reputation: 18002

So, you want to wait until your ProgressBar is hidden. You can either create an idling resource or use a custom ViewAction as this one:

/**
 * Perform action of waiting until the element is accessible & not shown.
 * @param viewId The id of the view to wait for.
 * @param millis The timeout of until when to wait for.
 */
public static ViewAction waitUntilNotShown(final int viewId, final long millis) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isRoot();
        }

        @Override
        public String getDescription() {
            return "wait for a specific view with id <" + viewId + "> is hidden during " + millis + " millis.";
        }

        @Override
        public void perform(final UiController uiController, final View view) {
            uiController.loopMainThreadUntilIdle();
            final long startTime = System.currentTimeMillis();
            final long endTime = startTime + millis;
            final Matcher<View> viewMatcher = withId(viewId);

            do {
                for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
                    // found view with required ID
                    if (viewMatcher.matches(child) && !child.isShown()) {
                        return;
                    }
                }

                uiController.loopMainThreadForAtLeast(50);
            }
            while (System.currentTimeMillis() < endTime);

            // timeout happens
            throw new PerformException.Builder()
                    .withActionDescription(this.getDescription())
                    .withViewDescription(HumanReadables.describe(view))
                    .withCause(new TimeoutException())
                    .build();
        }
    };
}

And you can use it this way:

onView(isRoot()).perform(waitUntilNotShown(R.id.theIdToWaitFor, 5000));

changing theIdToWaitFor with the specific id of your ProgressBar and updating the timeout of 5 secs (5000 millis) if necessary.

However, depending on which test you are doing, if this is not an integration test it's better not to make real api calls.

Upvotes: 2

Related Questions