1/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.swiperefreshlayout.widget;
18
19import static android.support.test.espresso.Espresso.onView;
20import static android.support.test.espresso.matcher.ViewMatchers.withId;
21
22import static org.junit.Assert.assertEquals;
23import static org.junit.Assert.assertFalse;
24import static org.junit.Assert.assertTrue;
25import static org.mockito.Mockito.any;
26import static org.mockito.Mockito.eq;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.times;
29import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.when;
31
32import android.support.test.espresso.action.ViewActions;
33import android.support.test.filters.LargeTest;
34import android.support.test.filters.MediumTest;
35import android.support.test.filters.SmallTest;
36import android.support.test.rule.ActivityTestRule;
37import android.support.test.runner.AndroidJUnit4;
38import android.view.View;
39
40import androidx.swiperefreshlayout.test.R;
41import androidx.testutils.PollingCheck;
42
43import org.junit.Before;
44import org.junit.Rule;
45import org.junit.Test;
46import org.junit.runner.RunWith;
47
48import java.util.concurrent.CountDownLatch;
49import java.util.concurrent.TimeUnit;
50
51/**
52 * Tests SwipeRefreshLayout widget.
53 */
54@RunWith(AndroidJUnit4.class)
55public class SwipeRefreshLayoutTest {
56    @Rule
57    public final ActivityTestRule<SwipeRefreshLayoutActivity> mActivityTestRule =
58            new ActivityTestRule<>(SwipeRefreshLayoutActivity.class);
59
60    private static final long TIMEOUT = 1000;
61    private static final int INVALID_SIZE = 1000;
62
63    private SwipeRefreshLayout mSwipeRefresh;
64
65    @Before
66    public void setUp() {
67        mSwipeRefresh = mActivityTestRule.getActivity().findViewById(R.id.swipe_refresh);
68    }
69
70    @Test
71    @MediumTest
72    public void testStartAndStopRefreshing() throws Throwable {
73        SwipeRefreshLayout.OnRefreshListener mockListener =
74                mock(SwipeRefreshLayout.OnRefreshListener.class);
75        mSwipeRefresh.setOnRefreshListener(mockListener);
76
77        assertFalse(mSwipeRefresh.isRefreshing());
78        for (int i = 0; i < 5; i++) {
79            onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setRefreshing());
80            assertTrue(mSwipeRefresh.isRefreshing());
81
82            // onView(..).perform(..) does not work when views are animated.
83            // Therefore this is using a posted task to turn off refreshing.
84            mSwipeRefresh.getHandler().post(new Runnable() {
85                @Override
86                public void run() {
87                    mSwipeRefresh.setRefreshing(false);
88                }
89            });
90
91            PollingCheck.waitFor(TIMEOUT, new PollingCheck.PollingCheckCondition() {
92                @Override
93                public boolean canProceed() {
94                    return !mSwipeRefresh.isRefreshing();
95                }
96            });
97        }
98        verify(mockListener, times(0)).onRefresh();
99    }
100
101    @Test
102    @MediumTest
103    public void testSwipeDownToRefresh() throws Throwable {
104        assertFalse(mSwipeRefresh.isRefreshing());
105
106        swipeToRefreshVerifyThenStopRefreshing(true);
107    }
108
109    @Test
110    @SmallTest
111    public void testSetSize() throws Throwable {
112        float density = mSwipeRefresh.getResources().getDisplayMetrics().density;
113        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
114                mSwipeRefresh.getProgressCircleDiameter());
115        onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setSize(SwipeRefreshLayout.LARGE));
116        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER_LARGE * density),
117                mSwipeRefresh.getProgressCircleDiameter());
118        onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setSize(SwipeRefreshLayout.DEFAULT));
119        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
120                mSwipeRefresh.getProgressCircleDiameter());
121        onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setSize(SwipeRefreshLayout.DEFAULT));
122        onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setSize(INVALID_SIZE));
123        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
124                mSwipeRefresh.getProgressCircleDiameter());
125    }
126
127    @Test
128    @SmallTest
129    public void testSetOnChildScrollUpCallback() throws Throwable {
130        SwipeRefreshLayout.OnChildScrollUpCallback mockCallback =
131                mock(SwipeRefreshLayout.OnChildScrollUpCallback.class);
132        when(mockCallback.canChildScrollUp(eq(mSwipeRefresh), any(View.class)))
133                .thenReturn(true)
134                .thenReturn(true)
135                .thenReturn(false)
136                .thenReturn(false);
137        mSwipeRefresh.setOnChildScrollUpCallback(mockCallback);
138        assertTrue(mSwipeRefresh.canChildScrollUp());
139        assertTrue(mSwipeRefresh.canChildScrollUp());
140        assertFalse(mSwipeRefresh.canChildScrollUp());
141        assertFalse(mSwipeRefresh.canChildScrollUp());
142    }
143
144    @Test
145    @LargeTest
146    public void testSwipeDownToRefreshInitiallyDisabled() throws Throwable {
147        mActivityTestRule.runOnUiThread(new Runnable() {
148            @Override
149            public void run() {
150                mActivityTestRule.getActivity().setContentView(
151                        R.layout.swipe_refresh_layout_disabled_activity);
152            }
153        });
154        mSwipeRefresh = (SwipeRefreshLayout) mActivityTestRule.getActivity().findViewById(
155                R.id.swipe_refresh);
156
157        assertFalse(mSwipeRefresh.isRefreshing());
158
159        swipeToRefreshVerifyThenStopRefreshing(false);
160
161        onView(withId(R.id.swipe_refresh)).perform(SwipeRefreshLayoutActions.setEnabled(true));
162
163        swipeToRefreshVerifyThenStopRefreshing(true);
164    }
165
166    private void swipeToRefreshVerifyThenStopRefreshing(boolean expectRefreshing) throws Throwable {
167        final CountDownLatch latch = new CountDownLatch(1);
168        SwipeRefreshLayout.OnRefreshListener listener = new SwipeRefreshLayout.OnRefreshListener() {
169            @Override
170            public void onRefresh() {
171                latch.countDown();
172                assertTrue(mSwipeRefresh.isRefreshing());
173                mSwipeRefresh.setRefreshing(false);
174            }
175        };
176        mSwipeRefresh.setOnRefreshListener(listener);
177        onView(withId(R.id.content)).perform(ViewActions.swipeDown());
178        if (expectRefreshing) {
179            assertTrue("SwipeRefreshLayout never started refreshing",
180                    latch.await(500, TimeUnit.MILLISECONDS));
181        } else {
182            assertFalse("SwipeRefreshLayout unexpectedly started refreshing",
183                    latch.await(500, TimeUnit.MILLISECONDS));
184        }
185    }
186}
187