Commit a20473ce authored by Xing Liu's avatar Xing Liu Committed by Commit Bot

Download home: Fix a flaky test with RecyclerView issue.

In devices with small screen, "page 1" can fall outside of the view
port. We have to scroll to make the recycler view create the view
holder in memory.

About view port:
1. RecyclerView won't create view holder outside view port to save memory.
2. IsDisplay() won't check things outside view port.
3. In order to verify stuff outside view port, we have to scroll to a
particular view holder or position.

To scroll, there are a couple of ways:
1. Use any of 3 RecyclerViewActions.* API.
2. Implement our own ViewAction for RecyclerView, and scroll with the recycler view handle.

Bug: 1039491
Change-Id: I1669370abf595140313fc8cfcf2728e12e3b3389
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2411557Reviewed-by: default avatarShakti Sahu <shaktisahu@chromium.org>
Commit-Queue: Xing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807128}
parent eed49344
......@@ -77,6 +77,7 @@ class DateOrderedListView {
mView.invalidateItemDecorations();
}
};
mView.setId(R.id.download_home_recycler_view);
mView.setHasFixedSize(true);
((DefaultItemAnimator) mView.getItemAnimator()).setSupportsChangeAnimations(false);
mView.getItemAnimator().setMoveDuration(0);
......
......@@ -30,10 +30,15 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import androidx.test.espresso.action.ViewActions;
import androidx.test.espresso.contrib.RecyclerViewActions;
import androidx.test.espresso.matcher.BoundedMatcher;
import androidx.test.filters.MediumTest;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.Rule;
import org.junit.Test;
......@@ -45,12 +50,12 @@ import org.chromium.base.Callback;
import org.chromium.base.DiscardableReferencePool;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.task.PostTask;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.FlakyTest;
import org.chromium.base.test.util.JniMocker;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.download.DownloadLaterPromptStatus;
import org.chromium.chrome.browser.download.R;
import org.chromium.chrome.browser.download.home.list.holder.ListItemViewHolder;
import org.chromium.chrome.browser.download.home.rename.RenameUtils;
import org.chromium.chrome.browser.download.home.toolbar.DownloadHomeToolbar;
import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory;
......@@ -77,6 +82,7 @@ import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.test.util.DummyUiActivityTestCase;
import org.chromium.ui.test.util.UiRestriction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
......@@ -106,6 +112,27 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
private DiscardableReferencePool mDiscardableReferencePool;
/**
* Returns a Matcher to find a particular {@link ViewHolder} that contains certain text.
* @param text The text that the view holder has in its view hierarchy.
*/
private static Matcher<ViewHolder> hasTextInViewHolder(String text) {
return new BoundedMatcher<ViewHolder, ListItemViewHolder>(ListItemViewHolder.class) {
@Override
public void describeTo(Description description) {
description.appendText("has text: " + text);
}
@Override
protected boolean matchesSafely(ListItemViewHolder listItemViewHolder) {
ArrayList<View> outViews = new ArrayList<>();
listItemViewHolder.itemView.findViewsWithText(
outViews, text, View.FIND_VIEWS_WITH_TEXT);
return !outViews.isEmpty();
}
};
}
@Override
public void setUpTest() throws Exception {
super.setUpTest();
......@@ -182,7 +209,6 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
@Test
@MediumTest
@DisabledTest(message = "https://crbug.com/1039491")
public void testLaunchingActivity() {
TestThreadUtils.runOnUiThreadBlocking(() -> { setUpUi(); });
......@@ -190,10 +216,15 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
onView(withText("Downloads")).check(matches(isDisplayed()));
// Shows the list items.
onView(withText("page 1")).check(matches(isDisplayed()));
onView(withText("page 2")).check(matches(isDisplayed()));
onView(withText("page 3")).check(matches(isDisplayed()));
onView(withText("page 4")).check(matches(isDisplayed()));
// The last item may be outside the view port, that recycler view won't create the view
// holder, so scroll to that view holder first.
onView(withId(R.id.download_home_recycler_view))
.perform(RecyclerViewActions.scrollToHolder(hasTextInViewHolder("page 1")));
onView(withText("page 1")).check(matches(isDisplayed()));
}
@Test
......@@ -463,6 +494,10 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
}
private void checkItemsDisplayed(boolean item0, boolean item1, boolean item2, boolean item3) {
// TODO(xingliu): Fix this properly. Some items may be outside the view port, that the
// recycler view won't create the view holder, and isDisplayed() will not check those items
// as well.
// See https://crbug.com/1039491.
onView(withText("page 1")).check(item0 ? matches(isDisplayed()) : doesNotExist());
onView(withText("page 2")).check(item1 ? matches(isDisplayed()) : doesNotExist());
onView(withText("page 3")).check(item2 ? matches(isDisplayed()) : doesNotExist());
......
......@@ -6,4 +6,5 @@
<resources>
<item name="circular_progress_view_action" type="id" />
<item name="circular_progress_view_progress" type="id" />
<item name="download_home_recycler_view" type="id" />
</resources>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment