Search code examples
android-testingandroid-espresso

Wait for view pager animations with espresso?


Trying to do some tests with a ViewPager.

I want to swipe between tabs, and I don't want to continue until the swipe is complete. But there doesn't appear to be a way to turn off the animation for the view pager (all animations under the developer options are disabled).

So this always results in a test failure, because the view pager hasn't completed it's animation, and so the view is not completely displayed yet:

// swipe left
onView(withId(R.id.viewpager)).check(matches(isDisplayed())).perform(swipeLeft());

// check to ensure that the next tab is completely visible.
onView(withId(R.id.next_tab)).check(matches(isCompletelyDisplayed()));

Is there an elegant or maybe even recommended way to do this, or am I stuck putting some kind of timed wait in there?


Solution

  • The IdlingResource @Simas suggests is actually pretty simple to implement:

    public class ViewPagerIdlingResource implements IdlingResource {
    
        private final String mName;
    
        private boolean mIdle = true; // Default to idle since we can't query the scroll state.
    
        private ResourceCallback mResourceCallback;
    
        public ViewPagerIdlingResource(ViewPager viewPager, String name) {
            viewPager.addOnPageChangeListener(new ViewPagerListener());
            mName = name;
        }
    
        @Override
        public String getName() {
            return mName;
        }
    
        @Override
        public boolean isIdleNow() {
            return mIdle;
        }
    
        @Override
        public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
            mResourceCallback = resourceCallback;
        }
    
        private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {
    
            @Override
            public void onPageScrollStateChanged(int state) {
                mIdle = (state == ViewPager.SCROLL_STATE_IDLE
                        // Treat dragging as idle, or Espresso will block itself when swiping.
                        || state == ViewPager.SCROLL_STATE_DRAGGING);
                if (mIdle && mResourceCallback != null) {
                    mResourceCallback.onTransitionToIdle();
                }
            }
        }
    }