| Index: chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
|
| diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
|
| index 9c9a2d0d086480726f561bed0cc0b79207a53432..4f488c0184ae6cd9b52a41ac3378d32756a53a89 100644
|
| --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
|
| +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
|
| @@ -7,26 +7,25 @@ package org.chromium.chrome.browser.ntp.cards;
|
| import static org.junit.Assert.assertEquals;
|
| import static org.junit.Assert.assertFalse;
|
| import static org.junit.Assert.assertNotEquals;
|
| -import static org.junit.Assert.assertThat;
|
| import static org.junit.Assert.assertTrue;
|
| -import static org.junit.Assert.fail;
|
| import static org.mockito.ArgumentMatchers.anyString;
|
| +import static org.mockito.ArgumentMatchers.eq;
|
| import static org.mockito.Mockito.atLeastOnce;
|
| import static org.mockito.Mockito.doNothing;
|
| +import static org.mockito.Mockito.inOrder;
|
| import static org.mockito.Mockito.mock;
|
| import static org.mockito.Mockito.reset;
|
| import static org.mockito.Mockito.spy;
|
| import static org.mockito.Mockito.times;
|
| import static org.mockito.Mockito.verify;
|
| +import static org.mockito.Mockito.verifyNoMoreInteractions;
|
| import static org.mockito.Mockito.when;
|
|
|
| -import static org.chromium.base.test.util.Matchers.greaterThanOrEqualTo;
|
| import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUtils.bindViewHolders;
|
| import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUtils.makeUiConfig;
|
| import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.createDummySuggestions;
|
| -import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.explainFailedExpectation;
|
| import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.registerCategory;
|
| -import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.viewTypeToString;
|
| +import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.stringify;
|
|
|
| import android.content.res.Resources;
|
| import android.support.v7.widget.RecyclerView;
|
| @@ -39,8 +38,13 @@ import org.junit.Rule;
|
| import org.junit.Test;
|
| import org.junit.runner.RunWith;
|
| import org.mockito.ArgumentCaptor;
|
| +import org.mockito.InOrder;
|
| import org.mockito.Mock;
|
| import org.mockito.MockitoAnnotations;
|
| +import org.mockito.exceptions.base.MockitoAssertionError;
|
| +import org.mockito.internal.verification.Times;
|
| +import org.mockito.internal.verification.api.VerificationDataInOrder;
|
| +import org.mockito.verification.VerificationMode;
|
| import org.robolectric.RuntimeEnvironment;
|
| import org.robolectric.annotation.Config;
|
| import org.robolectric.annotation.Implementation;
|
| @@ -57,6 +61,7 @@ import org.chromium.chrome.browser.ntp.ContextMenuManager;
|
| import org.chromium.chrome.browser.ntp.cards.SignInPromo.SigninObserver;
|
| import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
|
| import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
|
| +import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
|
| import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
|
| import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
|
| import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
|
| @@ -108,89 +113,119 @@ public class NewTabPageAdapterTest {
|
| * Stores information about a section that should be present in the adapter.
|
| */
|
| private static class SectionDescriptor {
|
| - public final int mNumSuggestions;
|
| + public boolean mHeader = true;
|
| + public final List<SnippetArticle> mSuggestions;
|
| public final boolean mStatusCard;
|
| - public boolean mActionButton;
|
| + public boolean mViewAllButton;
|
| + public boolean mFetchButton;
|
| public boolean mProgressItem;
|
| - public SnippetArticle mFirstItem;
|
|
|
| - public SectionDescriptor(int numSuggestions) {
|
| - mNumSuggestions = numSuggestions;
|
| - mStatusCard = numSuggestions == 0;
|
| + public SectionDescriptor(List<SnippetArticle> suggestions) {
|
| + mSuggestions = suggestions;
|
| + mStatusCard = suggestions.isEmpty();
|
| }
|
|
|
| - public SectionDescriptor withActionButton() {
|
| - mActionButton = true;
|
| + public SectionDescriptor withoutHeader() {
|
| + mHeader = false;
|
| return this;
|
| }
|
|
|
| - public SectionDescriptor withProgress() {
|
| - mProgressItem = true;
|
| + public SectionDescriptor withViewAllButton() {
|
| + mViewAllButton = true;
|
| + return this;
|
| + }
|
| +
|
| + public SectionDescriptor withFetchButton() {
|
| + mFetchButton = true;
|
| return this;
|
| }
|
|
|
| - public SectionDescriptor withFirstItem(SnippetArticle firstItem) {
|
| - mFirstItem = firstItem;
|
| + public SectionDescriptor withProgress() {
|
| + mProgressItem = true;
|
| return this;
|
| }
|
| }
|
|
|
| /**
|
| * Checks the list of items from the adapter against a sequence of expectation, which is
|
| - * expressed as a sequence of calls to the {@link #expect} methods.
|
| + * expressed as a sequence of calls to the {@code expect...()} methods.
|
| */
|
| private static class ItemsMatcher { // TODO(pke): Find better name.
|
| - private final TreeNode mTreeNode;
|
| - private int mCurrentIndex;
|
| + private final TreeNode mRoot;
|
| + private final NodeVisitor mVisitor = mock(NodeVisitor.class);
|
| + private final InOrder mInOrder = inOrder(mVisitor);
|
| +
|
| + /**
|
| + * The {@link org.mockito.internal.verification.Description} verification mode doesn't
|
| + * support in-order verification, so we use a custom verification mode that derives from the
|
| + * default one.
|
| + */
|
| + private final VerificationMode mVerification = new Times(1) {
|
| + @Override
|
| + public void verifyInOrder(VerificationDataInOrder data) {
|
| + try {
|
| + super.verifyInOrder(data);
|
| + } catch (MockitoAssertionError e) {
|
| + throw new MockitoAssertionError(e, stringify(mRoot));
|
| + }
|
| + }
|
| + };
|
|
|
| public ItemsMatcher(TreeNode root) {
|
| - mTreeNode = root;
|
| + mRoot = root;
|
| + root.visitItems(mVisitor);
|
| }
|
|
|
| - public void expect(@ItemViewType int expectedItemType) {
|
| - if (mCurrentIndex >= mTreeNode.getItemCount()) {
|
| - fail("Expected item of type " + viewTypeToString(expectedItemType)
|
| - + " but encountered end of list\n"
|
| - + explainFailedExpectation(mTreeNode, mCurrentIndex, expectedItemType));
|
| - }
|
| - if (mTreeNode.getItemViewType(mCurrentIndex) != expectedItemType) {
|
| - fail("Type mismatch at position " + mCurrentIndex + "\n"
|
| - + explainFailedExpectation(mTreeNode, mCurrentIndex, expectedItemType));
|
| + public void expectSection(SectionDescriptor descriptor) {
|
| + if (descriptor.mHeader) {
|
| + mInOrder.verify(mVisitor, mVerification).visitHeader();
|
| }
|
| - mCurrentIndex++;
|
| - }
|
| -
|
| - public void expect(SectionDescriptor descriptor) {
|
| - expect(ItemViewType.HEADER);
|
|
|
| - if (descriptor.mFirstItem != null) {
|
| - if (mTreeNode.getSuggestionAt(mCurrentIndex) != descriptor.mFirstItem) {
|
| - fail("Wrong item at position " + mCurrentIndex + "\n"
|
| - + explainFailedExpectation(
|
| - mTreeNode, mCurrentIndex, ItemViewType.SNIPPET));
|
| - }
|
| + for (SnippetArticle suggestion : descriptor.mSuggestions) {
|
| + mInOrder.verify(mVisitor, mVerification).visitSuggestion(eq(suggestion));
|
| }
|
|
|
| - for (int i = 1; i <= descriptor.mNumSuggestions; i++) {
|
| - expect(ItemViewType.SNIPPET);
|
| + if (descriptor.mStatusCard) {
|
| + mInOrder.verify(mVisitor, mVerification).visitNoSuggestionsItem();
|
| }
|
|
|
| - if (descriptor.mStatusCard) {
|
| - expect(ItemViewType.STATUS);
|
| + if (descriptor.mViewAllButton) {
|
| + mInOrder.verify(mVisitor, mVerification)
|
| + .visitActionItem(ContentSuggestionsAdditionalAction.VIEW_ALL);
|
| }
|
|
|
| - if (descriptor.mActionButton) {
|
| - // TODO(bauerb): Verify the action.
|
| - expect(ItemViewType.ACTION);
|
| + if (descriptor.mFetchButton) {
|
| + mInOrder.verify(mVisitor, mVerification)
|
| + .visitActionItem(ContentSuggestionsAdditionalAction.FETCH);
|
| }
|
|
|
| if (descriptor.mProgressItem) {
|
| - expect(ItemViewType.PROGRESS);
|
| + mInOrder.verify(mVisitor, mVerification).visitProgressItem();
|
| }
|
| }
|
|
|
| + public void expectAboveTheFoldItem() {
|
| + mInOrder.verify(mVisitor, mVerification).visitAboveTheFoldItem();
|
| + }
|
| +
|
| + public void expectAllDismissedItem() {
|
| + mInOrder.verify(mVisitor, mVerification).visitAllDismissedItem();
|
| + }
|
| +
|
| + public void expectFooter() {
|
| + mInOrder.verify(mVisitor, mVerification).visitFooter();
|
| + }
|
| +
|
| + public void expectSpacingItem() {
|
| + mInOrder.verify(mVisitor, mVerification).visitSpacingItem();
|
| + }
|
| +
|
| public void expectEnd() {
|
| - assertEquals(mTreeNode.getItemCount(), mCurrentIndex);
|
| + try {
|
| + verifyNoMoreInteractions(mVisitor);
|
| + } catch (MockitoAssertionError e) {
|
| + throw new MockitoAssertionError(e, stringify(mRoot));
|
| + }
|
| }
|
| }
|
|
|
| @@ -242,7 +277,7 @@ public class NewTabPageAdapterTest {
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
|
|
| - assertItemsFor(section(numSuggestions));
|
| + assertItemsFor(section(suggestions));
|
| }
|
|
|
| /**
|
| @@ -262,7 +297,7 @@ public class NewTabPageAdapterTest {
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
|
|
| - assertItemsFor(section(numSuggestions));
|
| + assertItemsFor(section(suggestions));
|
| }
|
|
|
| /**
|
| @@ -274,12 +309,12 @@ public class NewTabPageAdapterTest {
|
| List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGORY);
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(4));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // If we get told that the category is enabled, we just leave the current suggestions do not
|
| // clear them.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| - assertItemsFor(section(4));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // When the category is disabled, the section should go away completely.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
|
| @@ -293,7 +328,7 @@ public class NewTabPageAdapterTest {
|
|
|
| // After a full refresh, the adapter should accept suggestions again.
|
| mSource.fireFullRefreshRequired();
|
| - assertItemsFor(section(6));
|
| + assertItemsFor(section(suggestions));
|
| }
|
|
|
| /**
|
| @@ -307,17 +342,17 @@ public class NewTabPageAdapterTest {
|
| // By default, status is INITIALIZING, so we can load suggestions.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // Add another suggestion.
|
| - suggestions.add(new SnippetArticle(TEST_CATEGORY, "https://site.com/url1", "title1", "pub1",
|
| - "txt1", "https://site.com/url1", 0, 0, 0));
|
| + suggestions.add(new SnippetArticle(TEST_CATEGORY, "https://site.com/url3", "title3", "pub3",
|
| + "txt3", "https://site.com/url3", 0, 0, 0));
|
|
|
| // When the provider is removed, we should not be able to load suggestions. The UI should
|
| // stay the same though.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| + assertItemsFor(section(suggestions.subList(0, 3)));
|
|
|
| // INITIALIZING lets us load suggestions still.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INITIALIZING);
|
| @@ -327,7 +362,7 @@ public class NewTabPageAdapterTest {
|
| // The adapter should now be waiting for new suggestions and the fourth one should appear.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(4));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // When the category gets disabled, the section should go away and not load any suggestions.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
|
| @@ -370,7 +405,7 @@ public class NewTabPageAdapterTest {
|
| List<SnippetArticle> suggestions = createDummySuggestions(5, TEST_CATEGORY);
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(5));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // When the category goes away with a hard error, the section is cleared from the UI.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.LOADING_ERROR);
|
| @@ -384,7 +419,7 @@ public class NewTabPageAdapterTest {
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| reloadNtp();
|
| - assertItemsFor(section(5));
|
| + assertItemsFor(section(suggestions));
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
|
| assertItemsFor();
|
|
|
| @@ -401,12 +436,12 @@ public class NewTabPageAdapterTest {
|
| List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGORY);
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(4));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // When the category switches to NOT_PROVIDED, UI stays the same.
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED);
|
| mSource.silentlyRemoveCategory(TEST_CATEGORY);
|
| - assertItemsFor(section(4));
|
| + assertItemsFor(section(suggestions));
|
|
|
| reloadNtp();
|
| assertItemsFor();
|
| @@ -431,17 +466,17 @@ public class NewTabPageAdapterTest {
|
| mSource.setSuggestionsForCategory(otherCategory, otherSuggestions);
|
|
|
| reloadNtp();
|
| - assertItemsFor(section(4), section(2));
|
| + assertItemsFor(section(suggestions), section(otherSuggestions));
|
|
|
| // Bind the whole section - indicate that it is being viewed.
|
| bindViewHolders(mAdapter.getSectionListForTesting().getSectionForTesting(otherCategory));
|
|
|
| List<SnippetArticle> newSuggestions = createDummySuggestions(3, TEST_CATEGORY, "new");
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, newSuggestions);
|
| - assertItemsFor(section(3), section(2));
|
| + assertItemsFor(section(newSuggestions), section(otherSuggestions));
|
|
|
| reloadNtp();
|
| - assertItemsFor(section(3), section(2));
|
| + assertItemsFor(section(newSuggestions), section(otherSuggestions));
|
| }
|
|
|
| /** Tests whether a section stays visible if empty, if required. */
|
| @@ -464,12 +499,12 @@ public class NewTabPageAdapterTest {
|
| Collections.unmodifiableList(createDummySuggestions(3, TEST_CATEGORY));
|
| suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // 1.3 - When all suggestions are dismissed
|
| SuggestionsSection section =
|
| mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CATEGORY);
|
| - assertSectionMatches(section(3), section);
|
| + assertSectionMatches(section(suggestions), section);
|
| section.removeSuggestionById(suggestions.get(0).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(1).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(2).mIdWithinCategory);
|
| @@ -499,7 +534,7 @@ public class NewTabPageAdapterTest {
|
| */
|
| @Test
|
| @Feature({"Ntp"})
|
| - public void testMoreButton() {
|
| + public void testViewAllButton() {
|
| // Part 1: With "View All" action
|
| FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource();
|
| suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INITIALIZING);
|
| @@ -512,23 +547,23 @@ public class NewTabPageAdapterTest {
|
| // 1.1 - Initial state.
|
| when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource);
|
| reloadNtp();
|
| - assertItemsFor(sectionWithStatusCard().withActionButton().withProgress());
|
| + assertItemsFor(sectionWithStatusCard().withViewAllButton().withProgress());
|
|
|
| // 1.2 - With suggestions.
|
| List<SnippetArticle> suggestions =
|
| Collections.unmodifiableList(createDummySuggestions(3, TEST_CATEGORY));
|
| suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3).withActionButton());
|
| + assertItemsFor(section(suggestions).withViewAllButton());
|
|
|
| // 1.3 - When all suggestions are dismissed.
|
| SuggestionsSection section =
|
| mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CATEGORY);
|
| - assertSectionMatches(section(3).withActionButton(), section);
|
| + assertSectionMatches(section(suggestions).withViewAllButton(), section);
|
| section.removeSuggestionById(suggestions.get(0).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(1).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(2).mIdWithinCategory);
|
| - assertItemsFor(sectionWithStatusCard().withActionButton());
|
| + assertItemsFor(sectionWithStatusCard().withViewAllButton());
|
|
|
| // Part 1: Without "View All" action
|
| suggestionsSource = new FakeSuggestionsSource();
|
| @@ -544,11 +579,11 @@ public class NewTabPageAdapterTest {
|
| // 2.2 - With suggestions.
|
| suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| + assertItemsFor(section(suggestions));
|
|
|
| // 2.3 - When all suggestions are dismissed.
|
| section = mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CATEGORY);
|
| - assertSectionMatches(section(3), section);
|
| + assertSectionMatches(section(suggestions), section);
|
| section.removeSuggestionById(suggestions.get(0).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(1).mIdWithinCategory);
|
| section.removeSuggestionById(suggestions.get(2).mIdWithinCategory);
|
| @@ -556,6 +591,70 @@ public class NewTabPageAdapterTest {
|
| }
|
|
|
| /**
|
| + * Tests that the more button is shown for sections that declare it.
|
| + */
|
| + @Test
|
| + @Feature({"Ntp"})
|
| + public void testFetchButton() {
|
| + @CategoryInt
|
| + final int category = TEST_CATEGORY;
|
| +
|
| + // Part 1: With "Fetch more" action
|
| + FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource();
|
| + suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
|
| + suggestionsSource.setInfoForCategory(category,
|
| + new CategoryInfoBuilder(category)
|
| + .withAction(ContentSuggestionsAdditionalAction.FETCH)
|
| + .showIfEmpty()
|
| + .build());
|
| +
|
| + // 1.1 - Initial state.
|
| + when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource);
|
| + reloadNtp();
|
| + assertItemsFor(sectionWithStatusCard().withFetchButton().withProgress());
|
| +
|
| + // 1.2 - With suggestions.
|
| + List<SnippetArticle> articles =
|
| + Collections.unmodifiableList(createDummySuggestions(3, category));
|
| + suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE);
|
| + suggestionsSource.setSuggestionsForCategory(category, articles);
|
| + assertItemsFor(section(articles).withFetchButton());
|
| +
|
| + // 1.3 - When all suggestions are dismissed.
|
| + SuggestionsSection section =
|
| + mAdapter.getSectionListForTesting().getSectionForTesting(category);
|
| + assertSectionMatches(section(articles).withFetchButton(), section);
|
| + section.removeSuggestionById(articles.get(0).mIdWithinCategory);
|
| + section.removeSuggestionById(articles.get(1).mIdWithinCategory);
|
| + section.removeSuggestionById(articles.get(2).mIdWithinCategory);
|
| + assertItemsFor(sectionWithStatusCard().withFetchButton());
|
| +
|
| + // Part 1: Without "Fetch more" action
|
| + suggestionsSource = new FakeSuggestionsSource();
|
| + suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
|
| + suggestionsSource.setInfoForCategory(
|
| + category, new CategoryInfoBuilder(category).showIfEmpty().build());
|
| +
|
| + // 2.1 - Initial state.
|
| + when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource);
|
| + reloadNtp();
|
| + assertItemsFor(sectionWithStatusCard().withProgress());
|
| +
|
| + // 2.2 - With suggestions.
|
| + suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE);
|
| + suggestionsSource.setSuggestionsForCategory(category, articles);
|
| + assertItemsFor(section(articles));
|
| +
|
| + // 2.3 - When all suggestions are dismissed.
|
| + section = mAdapter.getSectionListForTesting().getSectionForTesting(category);
|
| + assertSectionMatches(section(articles), section);
|
| + section.removeSuggestionById(articles.get(0).mIdWithinCategory);
|
| + section.removeSuggestionById(articles.get(1).mIdWithinCategory);
|
| + section.removeSuggestionById(articles.get(2).mIdWithinCategory);
|
| + assertItemsFor(sectionWithStatusCard());
|
| + }
|
| +
|
| + /**
|
| * Tests that invalidated suggestions are immediately removed.
|
| */
|
| @Test
|
| @@ -564,12 +663,11 @@ public class NewTabPageAdapterTest {
|
| List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGORY);
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| - assertArticlesEqual(suggestions, 2, 5);
|
| + assertItemsFor(section(suggestions));
|
|
|
| SnippetArticle removed = suggestions.remove(1);
|
| mSource.fireSuggestionInvalidated(TEST_CATEGORY, removed.mIdWithinCategory);
|
| - assertArticlesEqual(suggestions, 2, 4);
|
| + assertItemsFor(section(suggestions));
|
| }
|
|
|
| /**
|
| @@ -581,7 +679,7 @@ public class NewTabPageAdapterTest {
|
| List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGORY);
|
| mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| - assertItemsFor(section(3));
|
| + assertItemsFor(section(suggestions));
|
|
|
| int dynamicCategory1 = 1010;
|
| List<SnippetArticle> dynamics1 = createDummySuggestions(5, dynamicCategory1);
|
| @@ -593,7 +691,7 @@ public class NewTabPageAdapterTest {
|
| mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1);
|
| reloadNtp();
|
|
|
| - assertItemsFor(section(3), section(5).withActionButton());
|
| + assertItemsFor(section(suggestions), section(dynamics1).withViewAllButton());
|
|
|
| int dynamicCategory2 = 1011;
|
| List<SnippetArticle> dynamics2 = createDummySuggestions(11, dynamicCategory2);
|
| @@ -602,7 +700,33 @@ public class NewTabPageAdapterTest {
|
| mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE);
|
| mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2);
|
| reloadNtp();
|
| - assertItemsFor(section(3), section(5).withActionButton(), section(11));
|
| + assertItemsFor(
|
| + section(suggestions), section(dynamics1).withViewAllButton(), section(dynamics2));
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"Ntp"})
|
| + public void testArticlesForYouSection() {
|
| + // Show one section of suggestions from the test category, and one section with Articles for
|
| + // You.
|
| + List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGORY);
|
| + mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
|
| + mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions);
|
| +
|
| + mSource.setInfoForCategory(KnownCategories.ARTICLES,
|
| + new CategoryInfoBuilder(KnownCategories.ARTICLES).build());
|
| + mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
|
| + List<SnippetArticle> articles = createDummySuggestions(3, KnownCategories.ARTICLES);
|
| + mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, articles);
|
| +
|
| + reloadNtp();
|
| + assertItemsFor(section(suggestions), section(articles));
|
| +
|
| + // Remove the test category section. The remaining lone Articles for You section should not
|
| + // have a header.
|
| + mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED);
|
| + reloadNtp();
|
| + assertItemsFor(section(articles).withoutHeader());
|
| }
|
|
|
| /**
|
| @@ -962,7 +1086,7 @@ public class NewTabPageAdapterTest {
|
| */
|
| private void assertSectionMatches(SectionDescriptor descriptor, SuggestionsSection section) {
|
| ItemsMatcher matcher = new ItemsMatcher(section);
|
| - matcher.expect(descriptor);
|
| + matcher.expectSection(descriptor);
|
| matcher.expectEnd();
|
| }
|
|
|
| @@ -975,28 +1099,28 @@ public class NewTabPageAdapterTest {
|
| */
|
| private void assertItemsFor(SectionDescriptor... descriptors) {
|
| ItemsMatcher matcher = new ItemsMatcher(mAdapter.getRootForTesting());
|
| - matcher.expect(ItemViewType.ABOVE_THE_FOLD);
|
| - for (SectionDescriptor descriptor : descriptors) matcher.expect(descriptor);
|
| + matcher.expectAboveTheFoldItem();
|
| + for (SectionDescriptor descriptor : descriptors) matcher.expectSection(descriptor);
|
| if (descriptors.length == 0) {
|
| - matcher.expect(ItemViewType.ALL_DISMISSED);
|
| + matcher.expectAllDismissedItem();
|
| } else {
|
| - matcher.expect(ItemViewType.FOOTER);
|
| + matcher.expectFooter();
|
| }
|
| - matcher.expect(ItemViewType.SPACING);
|
| + matcher.expectSpacingItem();
|
| matcher.expectEnd();
|
| }
|
|
|
| /**
|
| * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a section with
|
| * {@code numSuggestions} cards in it.
|
| - * @param numSuggestions The number of suggestions in the section. If there are zero, use either
|
| + * @param suggestions The list of suggestions in the section. If the list is empty, use either
|
| * no section at all (if it is not displayed) or
|
| * {@link #sectionWithStatusCard()}.
|
| * @return A descriptor for the section.
|
| */
|
| - private SectionDescriptor section(int numSuggestions) {
|
| - assert numSuggestions > 0;
|
| - return new SectionDescriptor(numSuggestions);
|
| + private SectionDescriptor section(List<SnippetArticle> suggestions) {
|
| + assert !suggestions.isEmpty();
|
| + return new SectionDescriptor(suggestions);
|
| }
|
|
|
| /**
|
| @@ -1005,7 +1129,7 @@ public class NewTabPageAdapterTest {
|
| * @return A descriptor for the section.
|
| */
|
| private SectionDescriptor sectionWithStatusCard() {
|
| - return new SectionDescriptor(0);
|
| + return new SectionDescriptor(Collections.<SnippetArticle>emptyList());
|
| }
|
|
|
| private void reloadNtp() {
|
| @@ -1015,13 +1139,6 @@ public class NewTabPageAdapterTest {
|
| mAdapter.refreshSuggestions();
|
| }
|
|
|
| - private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) {
|
| - assertThat(mAdapter.getItemCount(), greaterThanOrEqualTo(end));
|
| - for (int i = start; i < end; i++) {
|
| - assertEquals(articles.get(i - start), mAdapter.getSuggestionAt(i));
|
| - }
|
| - }
|
| -
|
| private boolean isSignInPromoVisible() {
|
| return mAdapter.getFirstPositionForType(ItemViewType.PROMO) != RecyclerView.NO_POSITION;
|
| }
|
|
|