OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.ntp.cards; | 5 package org.chromium.chrome.browser.ntp.cards; |
6 | 6 |
7 import static org.junit.Assert.assertEquals; | 7 import static org.junit.Assert.assertEquals; |
8 import static org.junit.Assert.assertFalse; | 8 import static org.junit.Assert.assertFalse; |
9 import static org.junit.Assert.assertNotEquals; | 9 import static org.junit.Assert.assertNotEquals; |
10 import static org.junit.Assert.assertThat; | |
11 import static org.junit.Assert.assertTrue; | 10 import static org.junit.Assert.assertTrue; |
12 import static org.junit.Assert.fail; | |
13 import static org.mockito.ArgumentMatchers.anyString; | 11 import static org.mockito.ArgumentMatchers.anyString; |
12 import static org.mockito.ArgumentMatchers.eq; | |
14 import static org.mockito.Mockito.atLeastOnce; | 13 import static org.mockito.Mockito.atLeastOnce; |
15 import static org.mockito.Mockito.doNothing; | 14 import static org.mockito.Mockito.doNothing; |
15 import static org.mockito.Mockito.inOrder; | |
16 import static org.mockito.Mockito.mock; | 16 import static org.mockito.Mockito.mock; |
17 import static org.mockito.Mockito.reset; | 17 import static org.mockito.Mockito.reset; |
18 import static org.mockito.Mockito.spy; | 18 import static org.mockito.Mockito.spy; |
19 import static org.mockito.Mockito.times; | 19 import static org.mockito.Mockito.times; |
20 import static org.mockito.Mockito.verify; | 20 import static org.mockito.Mockito.verify; |
21 import static org.mockito.Mockito.verifyNoMoreInteractions; | |
21 import static org.mockito.Mockito.when; | 22 import static org.mockito.Mockito.when; |
22 | 23 |
23 import static org.chromium.base.test.util.Matchers.greaterThanOrEqualTo; | |
24 import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUt ils.bindViewHolders; | 24 import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUt ils.bindViewHolders; |
25 import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUt ils.makeUiConfig; | 25 import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUt ils.makeUiConfig; |
26 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.createDummySuggestions; | 26 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.createDummySuggestions; |
27 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.explainFailedExpectation; | |
28 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.registerCategory; | 27 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.registerCategory; |
29 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.viewTypeToString; | 28 import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestio nsTestUtils.stringify; |
30 | 29 |
31 import android.content.res.Resources; | 30 import android.content.res.Resources; |
32 import android.support.v7.widget.RecyclerView; | 31 import android.support.v7.widget.RecyclerView; |
33 import android.support.v7.widget.RecyclerView.AdapterDataObserver; | 32 import android.support.v7.widget.RecyclerView.AdapterDataObserver; |
34 import android.view.View; | 33 import android.view.View; |
35 | 34 |
36 import org.junit.After; | 35 import org.junit.After; |
37 import org.junit.Before; | 36 import org.junit.Before; |
38 import org.junit.Rule; | 37 import org.junit.Rule; |
39 import org.junit.Test; | 38 import org.junit.Test; |
40 import org.junit.runner.RunWith; | 39 import org.junit.runner.RunWith; |
41 import org.mockito.ArgumentCaptor; | 40 import org.mockito.ArgumentCaptor; |
41 import org.mockito.InOrder; | |
42 import org.mockito.Mock; | 42 import org.mockito.Mock; |
43 import org.mockito.MockitoAnnotations; | 43 import org.mockito.MockitoAnnotations; |
44 import org.mockito.exceptions.base.MockitoAssertionError; | |
45 import org.mockito.internal.verification.Times; | |
46 import org.mockito.internal.verification.api.VerificationDataInOrder; | |
47 import org.mockito.verification.VerificationMode; | |
44 import org.robolectric.RuntimeEnvironment; | 48 import org.robolectric.RuntimeEnvironment; |
45 import org.robolectric.annotation.Config; | 49 import org.robolectric.annotation.Config; |
46 import org.robolectric.annotation.Implementation; | 50 import org.robolectric.annotation.Implementation; |
47 import org.robolectric.annotation.Implements; | 51 import org.robolectric.annotation.Implements; |
48 import org.robolectric.shadows.ShadowResources; | 52 import org.robolectric.shadows.ShadowResources; |
49 | 53 |
50 import org.chromium.base.Callback; | 54 import org.chromium.base.Callback; |
51 import org.chromium.base.ContextUtils; | 55 import org.chromium.base.ContextUtils; |
52 import org.chromium.base.test.util.Feature; | 56 import org.chromium.base.test.util.Feature; |
53 import org.chromium.chrome.R; | 57 import org.chromium.chrome.R; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 @Mock | 103 @Mock |
100 private SigninManager mMockSigninManager; | 104 private SigninManager mMockSigninManager; |
101 @Mock | 105 @Mock |
102 private OfflinePageBridge mOfflinePageBridge; | 106 private OfflinePageBridge mOfflinePageBridge; |
103 @Mock | 107 @Mock |
104 private SuggestionsUiDelegate mUiDelegate; | 108 private SuggestionsUiDelegate mUiDelegate; |
105 | 109 |
106 /** | 110 /** |
107 * Stores information about a section that should be present in the adapter. | 111 * Stores information about a section that should be present in the adapter. |
108 */ | 112 */ |
109 private static class SectionDescriptor { | 113 private static class SectionDescriptor { |
dgn
2017/05/22 13:47:03
I think it would be nice to extract all of that fr
Bernhard Bauer
2017/05/23 16:40:27
I think it's a good idea, but can we do that in a
| |
110 public final int mNumSuggestions; | 114 public final List<SnippetArticle> mSuggestions; |
111 public final boolean mStatusCard; | 115 public final boolean mStatusCard; |
112 public boolean mActionButton; | 116 public boolean mViewAllButton; |
117 public boolean mFetchButton; | |
113 public boolean mProgressItem; | 118 public boolean mProgressItem; |
114 public SnippetArticle mFirstItem; | |
115 | 119 |
116 public SectionDescriptor(int numSuggestions) { | 120 public SectionDescriptor(List<SnippetArticle> suggestions) { |
117 mNumSuggestions = numSuggestions; | 121 mSuggestions = suggestions; |
118 mStatusCard = numSuggestions == 0; | 122 mStatusCard = suggestions.isEmpty(); |
119 } | 123 } |
120 | 124 |
121 public SectionDescriptor withActionButton() { | 125 public SectionDescriptor withViewAllButton() { |
122 mActionButton = true; | 126 mViewAllButton = true; |
127 return this; | |
128 } | |
129 | |
130 public SectionDescriptor withFetchButton() { | |
131 mFetchButton = true; | |
123 return this; | 132 return this; |
124 } | 133 } |
125 | 134 |
126 public SectionDescriptor withProgress() { | 135 public SectionDescriptor withProgress() { |
127 mProgressItem = true; | 136 mProgressItem = true; |
128 return this; | 137 return this; |
129 } | 138 } |
130 | |
131 public SectionDescriptor withFirstItem(SnippetArticle firstItem) { | |
132 mFirstItem = firstItem; | |
133 return this; | |
134 } | |
135 } | 139 } |
136 | 140 |
137 /** | 141 /** |
138 * Checks the list of items from the adapter against a sequence of expectati on, which is | 142 * Checks the list of items from the adapter against a sequence of expectati on, which is |
139 * expressed as a sequence of calls to the {@link #expect} methods. | 143 * expressed as a sequence of calls to the {@code expect...()} methods. |
140 */ | 144 */ |
141 private static class ItemsMatcher { // TODO(pke): Find better name. | 145 private static class ItemsMatcher { // TODO(pke): Find better name. |
142 private final TreeNode mTreeNode; | 146 private final TreeNode mRoot; |
143 private int mCurrentIndex; | 147 private final NodeVisitor mVisitor = mock(NodeVisitor.class); |
148 private final InOrder mInOrder = inOrder(mVisitor); | |
149 | |
150 /** | |
151 * The {@link org.mockito.internal.verification.Description} verificatio n mode doesn't | |
152 * support in-order verification, so we use a custom verification mode t hat derives from the | |
153 * default one. | |
154 */ | |
155 private final VerificationMode mVerification = new Times(1) { | |
156 @Override | |
157 public void verifyInOrder(VerificationDataInOrder data) { | |
158 try { | |
159 super.verifyInOrder(data); | |
160 } catch (MockitoAssertionError e) { | |
161 throw new MockitoAssertionError(e, stringify(mRoot)); | |
162 } | |
163 } | |
164 }; | |
144 | 165 |
145 public ItemsMatcher(TreeNode root) { | 166 public ItemsMatcher(TreeNode root) { |
146 mTreeNode = root; | 167 mRoot = root; |
168 root.visitItems(mVisitor); | |
147 } | 169 } |
148 | 170 |
149 public void expect(@ItemViewType int expectedItemType) { | 171 public void expectSection(SectionDescriptor descriptor) { |
150 if (mCurrentIndex >= mTreeNode.getItemCount()) { | 172 mInOrder.verify(mVisitor, mVerification).visitHeader(); |
dgn
2017/05/22 13:47:03
we can have sections without headers, if the secti
Bernhard Bauer
2017/05/23 16:40:27
That is true, good catch! It only applies to Artic
| |
151 fail("Expected item of type " + viewTypeToString(expectedItemTyp e) | 173 for (SnippetArticle suggestion : descriptor.mSuggestions) { |
152 + " but encountered end of list\n" | 174 mInOrder.verify(mVisitor, mVerification).visitSuggestion(eq(sugg estion)); |
153 + explainFailedExpectation(mTreeNode, mCurrentIndex, exp ectedItemType)); | |
154 } | |
155 if (mTreeNode.getItemViewType(mCurrentIndex) != expectedItemType) { | |
156 fail("Type mismatch at position " + mCurrentIndex + "\n" | |
157 + explainFailedExpectation(mTreeNode, mCurrentIndex, exp ectedItemType)); | |
158 } | |
159 mCurrentIndex++; | |
160 } | |
161 | |
162 public void expect(SectionDescriptor descriptor) { | |
163 expect(ItemViewType.HEADER); | |
164 | |
165 if (descriptor.mFirstItem != null) { | |
166 if (mTreeNode.getSuggestionAt(mCurrentIndex) != descriptor.mFirs tItem) { | |
167 fail("Wrong item at position " + mCurrentIndex + "\n" | |
168 + explainFailedExpectation( | |
169 mTreeNode, mCurrentIndex, ItemViewType.SNI PPET)); | |
170 } | |
171 } | |
172 | |
173 for (int i = 1; i <= descriptor.mNumSuggestions; i++) { | |
174 expect(ItemViewType.SNIPPET); | |
175 } | 175 } |
176 | 176 |
177 if (descriptor.mStatusCard) { | 177 if (descriptor.mStatusCard) { |
178 expect(ItemViewType.STATUS); | 178 mInOrder.verify(mVisitor, mVerification).visitNoSuggestionsItem( ); |
179 } | 179 } |
180 | 180 |
181 if (descriptor.mActionButton) { | 181 if (descriptor.mViewAllButton) { |
182 // TODO(bauerb): Verify the action. | 182 mInOrder.verify(mVisitor, mVerification) |
183 expect(ItemViewType.ACTION); | 183 .visitActionItem(ContentSuggestionsAdditionalAction.VIEW _ALL); |
184 } | |
185 | |
186 if (descriptor.mFetchButton) { | |
187 mInOrder.verify(mVisitor, mVerification) | |
188 .visitActionItem(ContentSuggestionsAdditionalAction.FETC H); | |
184 } | 189 } |
185 | 190 |
186 if (descriptor.mProgressItem) { | 191 if (descriptor.mProgressItem) { |
187 expect(ItemViewType.PROGRESS); | 192 mInOrder.verify(mVisitor, mVerification).visitProgressItem(); |
188 } | 193 } |
189 } | 194 } |
190 | 195 |
196 public void expectAboveTheFoldItem() { | |
197 mInOrder.verify(mVisitor, mVerification).visitAboveTheFoldItem(); | |
198 } | |
199 | |
200 public void expectAllDismissedItem() { | |
201 mInOrder.verify(mVisitor, mVerification).visitAllDismissedItem(); | |
202 } | |
203 | |
204 public void expectFooter() { | |
205 mInOrder.verify(mVisitor, mVerification).visitFooter(); | |
206 } | |
207 | |
208 public void expectSpacingItem() { | |
209 mInOrder.verify(mVisitor, mVerification).visitSpacingItem(); | |
210 } | |
211 | |
191 public void expectEnd() { | 212 public void expectEnd() { |
192 assertEquals(mTreeNode.getItemCount(), mCurrentIndex); | 213 try { |
214 verifyNoMoreInteractions(mVisitor); | |
215 } catch (MockitoAssertionError e) { | |
216 throw new MockitoAssertionError(e, stringify(mRoot)); | |
217 } | |
193 } | 218 } |
194 } | 219 } |
195 | 220 |
196 @Before | 221 @Before |
197 public void setUp() { | 222 public void setUp() { |
198 MockitoAnnotations.initMocks(this); | 223 MockitoAnnotations.initMocks(this); |
199 | 224 |
200 ContextUtils.initApplicationContextForTests(RuntimeEnvironment.applicati on); | 225 ContextUtils.initApplicationContextForTests(RuntimeEnvironment.applicati on); |
201 | 226 |
202 // Set empty variation params for the test. | 227 // Set empty variation params for the test. |
(...skipping 30 matching lines...) Expand all Loading... | |
233 @Test | 258 @Test |
234 @Feature({"Ntp"}) | 259 @Feature({"Ntp"}) |
235 public void testSuggestionLoading() { | 260 public void testSuggestionLoading() { |
236 assertItemsFor(sectionWithStatusCard().withProgress()); | 261 assertItemsFor(sectionWithStatusCard().withProgress()); |
237 | 262 |
238 final int numSuggestions = 3; | 263 final int numSuggestions = 3; |
239 List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions , TEST_CATEGORY); | 264 List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions , TEST_CATEGORY); |
240 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 265 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
241 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 266 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
242 | 267 |
243 assertItemsFor(section(numSuggestions)); | 268 assertItemsFor(section(suggestions)); |
244 } | 269 } |
245 | 270 |
246 /** | 271 /** |
247 * Tests that the adapter keeps listening for suggestion updates. | 272 * Tests that the adapter keeps listening for suggestion updates. |
248 */ | 273 */ |
249 @Test | 274 @Test |
250 @Feature({"Ntp"}) | 275 @Feature({"Ntp"}) |
251 public void testSuggestionLoadingInitiallyEmpty() { | 276 public void testSuggestionLoadingInitiallyEmpty() { |
252 // If we don't get anything, we should be in the same situation as the i nitial one. | 277 // If we don't get anything, we should be in the same situation as the i nitial one. |
253 mSource.setSuggestionsForCategory(TEST_CATEGORY, new ArrayList<SnippetAr ticle>()); | 278 mSource.setSuggestionsForCategory(TEST_CATEGORY, new ArrayList<SnippetAr ticle>()); |
254 assertItemsFor(sectionWithStatusCard().withProgress()); | 279 assertItemsFor(sectionWithStatusCard().withProgress()); |
255 | 280 |
256 // We should load new suggestions when we get notified about them. | 281 // We should load new suggestions when we get notified about them. |
257 final int numSuggestions = 5; | 282 final int numSuggestions = 5; |
258 | 283 |
259 List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions , TEST_CATEGORY); | 284 List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions , TEST_CATEGORY); |
260 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 285 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
261 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 286 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
262 | 287 |
263 assertItemsFor(section(numSuggestions)); | 288 assertItemsFor(section(suggestions)); |
264 } | 289 } |
265 | 290 |
266 /** | 291 /** |
267 * Tests that the adapter clears the suggestions when asked to. | 292 * Tests that the adapter clears the suggestions when asked to. |
268 */ | 293 */ |
269 @Test | 294 @Test |
270 @Feature({"Ntp"}) | 295 @Feature({"Ntp"}) |
271 public void testSuggestionClearing() { | 296 public void testSuggestionClearing() { |
272 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); | 297 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); |
273 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 298 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
274 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 299 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
275 assertItemsFor(section(4)); | 300 assertItemsFor(section(suggestions)); |
276 | 301 |
277 // If we get told that the category is enabled, we just leave the curren t suggestions do not | 302 // If we get told that the category is enabled, we just leave the curren t suggestions do not |
278 // clear them. | 303 // clear them. |
279 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 304 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
280 assertItemsFor(section(4)); | 305 assertItemsFor(section(suggestions)); |
281 | 306 |
282 // When the category is disabled, the section should go away completely. | 307 // When the category is disabled, the section should go away completely. |
283 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); | 308 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); |
284 assertItemsFor(); | 309 assertItemsFor(); |
285 | 310 |
286 // Now we're in the "all dismissed" state. No suggestions should be acce pted. | 311 // Now we're in the "all dismissed" state. No suggestions should be acce pted. |
287 suggestions = createDummySuggestions(6, TEST_CATEGORY); | 312 suggestions = createDummySuggestions(6, TEST_CATEGORY); |
288 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 313 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
289 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 314 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
290 assertItemsFor(); | 315 assertItemsFor(); |
291 | 316 |
292 // After a full refresh, the adapter should accept suggestions again. | 317 // After a full refresh, the adapter should accept suggestions again. |
293 mSource.fireFullRefreshRequired(); | 318 mSource.fireFullRefreshRequired(); |
294 assertItemsFor(section(6)); | 319 assertItemsFor(section(suggestions)); |
295 } | 320 } |
296 | 321 |
297 /** | 322 /** |
298 * Tests that the adapter loads suggestions only when the status is favorabl e. | 323 * Tests that the adapter loads suggestions only when the status is favorabl e. |
299 */ | 324 */ |
300 @Test | 325 @Test |
301 @Feature({"Ntp"}) | 326 @Feature({"Ntp"}) |
302 public void testSuggestionLoadingBlock() { | 327 public void testSuggestionLoadingBlock() { |
303 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); | 328 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); |
304 | 329 |
305 // By default, status is INITIALIZING, so we can load suggestions. | 330 // By default, status is INITIALIZING, so we can load suggestions. |
306 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 331 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
307 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 332 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
308 assertItemsFor(section(3)); | 333 assertItemsFor(section(suggestions)); |
309 | 334 |
310 // Add another suggestion. | 335 // Add another suggestion. |
311 suggestions.add(new SnippetArticle(TEST_CATEGORY, "https://site.com/url1 ", "title1", "pub1", | 336 suggestions.add(new SnippetArticle(TEST_CATEGORY, "https://site.com/url3 ", "title3", "pub3", |
312 "txt1", "https://site.com/url1", 0, 0, 0)); | 337 "txt3", "https://site.com/url3", 0, 0, 0)); |
313 | 338 |
314 // When the provider is removed, we should not be able to load suggestio ns. The UI should | 339 // When the provider is removed, we should not be able to load suggestio ns. The UI should |
315 // stay the same though. | 340 // stay the same though. |
316 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED) ; | 341 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED) ; |
317 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 342 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
318 assertItemsFor(section(3)); | 343 assertItemsFor(section(suggestions.subList(0, 3))); |
319 | 344 |
320 // INITIALIZING lets us load suggestions still. | 345 // INITIALIZING lets us load suggestions still. |
321 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INITIALIZING) ; | 346 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INITIALIZING) ; |
322 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 347 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
323 assertItemsFor(sectionWithStatusCard().withProgress()); | 348 assertItemsFor(sectionWithStatusCard().withProgress()); |
324 | 349 |
325 // The adapter should now be waiting for new suggestions and the fourth one should appear. | 350 // The adapter should now be waiting for new suggestions and the fourth one should appear. |
326 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 351 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
327 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 352 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
328 assertItemsFor(section(4)); | 353 assertItemsFor(section(suggestions)); |
329 | 354 |
330 // When the category gets disabled, the section should go away and not l oad any suggestions. | 355 // When the category gets disabled, the section should go away and not l oad any suggestions. |
331 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); | 356 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); |
332 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 357 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
333 assertItemsFor(); | 358 assertItemsFor(); |
334 } | 359 } |
335 | 360 |
336 /** | 361 /** |
337 * Tests how the loading indicator reacts to status changes. | 362 * Tests how the loading indicator reacts to status changes. |
338 */ | 363 */ |
(...skipping 22 matching lines...) Expand all Loading... | |
361 /** | 386 /** |
362 * Tests that the entire section disappears if its status switches to LOADIN G_ERROR or | 387 * Tests that the entire section disappears if its status switches to LOADIN G_ERROR or |
363 * CATEGORY_EXPLICITLY_DISABLED. Also tests that they are not shown when the NTP reloads. | 388 * CATEGORY_EXPLICITLY_DISABLED. Also tests that they are not shown when the NTP reloads. |
364 */ | 389 */ |
365 @Test | 390 @Test |
366 @Feature({"Ntp"}) | 391 @Feature({"Ntp"}) |
367 public void testSectionClearingWhenUnavailable() { | 392 public void testSectionClearingWhenUnavailable() { |
368 List<SnippetArticle> suggestions = createDummySuggestions(5, TEST_CATEGO RY); | 393 List<SnippetArticle> suggestions = createDummySuggestions(5, TEST_CATEGO RY); |
369 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 394 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
370 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 395 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
371 assertItemsFor(section(5)); | 396 assertItemsFor(section(suggestions)); |
372 | 397 |
373 // When the category goes away with a hard error, the section is cleared from the UI. | 398 // When the category goes away with a hard error, the section is cleared from the UI. |
374 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.LOADING_ERROR ); | 399 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.LOADING_ERROR ); |
375 assertItemsFor(); | 400 assertItemsFor(); |
376 | 401 |
377 // Same when loading a new NTP. | 402 // Same when loading a new NTP. |
378 reloadNtp(); | 403 reloadNtp(); |
379 assertItemsFor(); | 404 assertItemsFor(); |
380 | 405 |
381 // Same for CATEGORY_EXPLICITLY_DISABLED. | 406 // Same for CATEGORY_EXPLICITLY_DISABLED. |
382 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 407 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
383 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 408 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
384 reloadNtp(); | 409 reloadNtp(); |
385 assertItemsFor(section(5)); | 410 assertItemsFor(section(suggestions)); |
386 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); | 411 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.CATEGORY_EXPL ICITLY_DISABLED); |
387 assertItemsFor(); | 412 assertItemsFor(); |
388 | 413 |
389 reloadNtp(); | 414 reloadNtp(); |
390 assertItemsFor(); | 415 assertItemsFor(); |
391 } | 416 } |
392 | 417 |
393 /** | 418 /** |
394 * Tests that the UI remains untouched if a category switches to NOT_PROVIDE D. | 419 * Tests that the UI remains untouched if a category switches to NOT_PROVIDE D. |
395 */ | 420 */ |
396 @Test | 421 @Test |
397 @Feature({"Ntp"}) | 422 @Feature({"Ntp"}) |
398 public void testUIUntouchedWhenNotProvided() { | 423 public void testUIUntouchedWhenNotProvided() { |
399 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); | 424 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); |
400 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 425 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
401 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 426 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
402 assertItemsFor(section(4)); | 427 assertItemsFor(section(suggestions)); |
403 | 428 |
404 // When the category switches to NOT_PROVIDED, UI stays the same. | 429 // When the category switches to NOT_PROVIDED, UI stays the same. |
405 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED) ; | 430 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.NOT_PROVIDED) ; |
406 mSource.silentlyRemoveCategory(TEST_CATEGORY); | 431 mSource.silentlyRemoveCategory(TEST_CATEGORY); |
407 assertItemsFor(section(4)); | 432 assertItemsFor(section(suggestions)); |
408 | 433 |
409 reloadNtp(); | 434 reloadNtp(); |
410 assertItemsFor(); | 435 assertItemsFor(); |
411 } | 436 } |
412 | 437 |
413 /** | 438 /** |
414 * Tests that the UI updates on updated suggestions. | 439 * Tests that the UI updates on updated suggestions. |
415 */ | 440 */ |
416 @Test | 441 @Test |
417 @Feature({"Ntp"}) | 442 @Feature({"Ntp"}) |
418 public void testUIUpdatesOnNewSuggestionsWhenOtherSectionSeen() { | 443 public void testUIUpdatesOnNewSuggestionsWhenOtherSectionSeen() { |
419 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); | 444 List<SnippetArticle> suggestions = createDummySuggestions(4, TEST_CATEGO RY); |
420 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 445 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
421 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 446 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
422 | 447 |
423 @CategoryInt | 448 @CategoryInt |
424 final int otherCategory = TEST_CATEGORY + 1; | 449 final int otherCategory = TEST_CATEGORY + 1; |
425 List<SnippetArticle> otherSuggestions = createDummySuggestions(2, otherC ategory); | 450 List<SnippetArticle> otherSuggestions = createDummySuggestions(2, otherC ategory); |
426 mSource.setStatusForCategory(otherCategory, CategoryStatus.AVAILABLE); | 451 mSource.setStatusForCategory(otherCategory, CategoryStatus.AVAILABLE); |
427 mSource.setInfoForCategory( | 452 mSource.setInfoForCategory( |
428 otherCategory, new CategoryInfoBuilder(otherCategory).showIfEmpt y().build()); | 453 otherCategory, new CategoryInfoBuilder(otherCategory).showIfEmpt y().build()); |
429 mSource.setSuggestionsForCategory(otherCategory, otherSuggestions); | 454 mSource.setSuggestionsForCategory(otherCategory, otherSuggestions); |
430 | 455 |
431 reloadNtp(); | 456 reloadNtp(); |
432 assertItemsFor(section(4), section(2)); | 457 assertItemsFor(section(suggestions), section(otherSuggestions)); |
433 | 458 |
434 // Bind the whole section - indicate that it is being viewed. | 459 // Bind the whole section - indicate that it is being viewed. |
435 bindViewHolders(mAdapter.getSectionListForTesting().getSectionForTesting (otherCategory)); | 460 bindViewHolders(mAdapter.getSectionListForTesting().getSectionForTesting (otherCategory)); |
436 | 461 |
437 List<SnippetArticle> newSuggestions = createDummySuggestions(3, TEST_CAT EGORY, "new"); | 462 List<SnippetArticle> newSuggestions = createDummySuggestions(3, TEST_CAT EGORY, "new"); |
438 mSource.setSuggestionsForCategory(TEST_CATEGORY, newSuggestions); | 463 mSource.setSuggestionsForCategory(TEST_CATEGORY, newSuggestions); |
439 assertItemsFor(section(3), section(2)); | 464 assertItemsFor(section(newSuggestions), section(otherSuggestions)); |
440 | 465 |
441 reloadNtp(); | 466 reloadNtp(); |
442 assertItemsFor(section(3), section(2)); | 467 assertItemsFor(section(newSuggestions), section(otherSuggestions)); |
443 } | 468 } |
444 | 469 |
445 /** Tests whether a section stays visible if empty, if required. */ | 470 /** Tests whether a section stays visible if empty, if required. */ |
446 @Test | 471 @Test |
447 @Feature({"Ntp"}) | 472 @Feature({"Ntp"}) |
448 public void testSectionVisibleIfEmpty() { | 473 public void testSectionVisibleIfEmpty() { |
449 // Part 1: VisibleIfEmpty = true | 474 // Part 1: VisibleIfEmpty = true |
450 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); | 475 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); |
451 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); | 476 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); |
452 suggestionsSource.setInfoForCategory( | 477 suggestionsSource.setInfoForCategory( |
453 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpt y().build()); | 478 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpt y().build()); |
454 | 479 |
455 // 1.1 - Initial state | 480 // 1.1 - Initial state |
456 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | 481 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); |
457 reloadNtp(); | 482 reloadNtp(); |
458 assertItemsFor(sectionWithStatusCard().withProgress()); | 483 assertItemsFor(sectionWithStatusCard().withProgress()); |
459 | 484 |
460 // 1.2 - With suggestions | 485 // 1.2 - With suggestions |
461 List<SnippetArticle> suggestions = | 486 List<SnippetArticle> suggestions = |
462 Collections.unmodifiableList(createDummySuggestions(3, TEST_CATE GORY)); | 487 Collections.unmodifiableList(createDummySuggestions(3, TEST_CATE GORY)); |
463 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); | 488 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); |
464 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 489 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
465 assertItemsFor(section(3)); | 490 assertItemsFor(section(suggestions)); |
466 | 491 |
467 // 1.3 - When all suggestions are dismissed | 492 // 1.3 - When all suggestions are dismissed |
468 SuggestionsSection section = | 493 SuggestionsSection section = |
469 mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CA TEGORY); | 494 mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CA TEGORY); |
470 assertSectionMatches(section(3), section); | 495 assertSectionMatches(section(suggestions), section); |
471 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); | 496 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); |
472 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); | 497 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); |
473 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); | 498 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); |
474 assertItemsFor(sectionWithStatusCard()); | 499 assertItemsFor(sectionWithStatusCard()); |
475 | 500 |
476 // Part 2: VisibleIfEmpty = false | 501 // Part 2: VisibleIfEmpty = false |
477 suggestionsSource = new FakeSuggestionsSource(); | 502 suggestionsSource = new FakeSuggestionsSource(); |
478 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); | 503 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); |
479 suggestionsSource.setInfoForCategory( | 504 suggestionsSource.setInfoForCategory( |
480 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).build()); | 505 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).build()); |
481 | 506 |
482 // 2.1 - Initial state | 507 // 2.1 - Initial state |
483 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | 508 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); |
484 reloadNtp(); | 509 reloadNtp(); |
485 assertItemsFor(); | 510 assertItemsFor(); |
486 | 511 |
487 // 2.2 - With suggestions | 512 // 2.2 - With suggestions |
488 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); | 513 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); |
489 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 514 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
490 assertItemsFor(); | 515 assertItemsFor(); |
491 | 516 |
492 // 2.3 - When all suggestions are dismissed - N/A, suggestions don't get added. | 517 // 2.3 - When all suggestions are dismissed - N/A, suggestions don't get added. |
493 } | 518 } |
494 | 519 |
495 /** | 520 /** |
496 * Tests that the more button is shown for sections that declare it. | 521 * Tests that the more button is shown for sections that declare it. |
497 */ | 522 */ |
498 @Test | 523 @Test |
499 @Feature({"Ntp"}) | 524 @Feature({"Ntp"}) |
500 public void testMoreButton() { | 525 public void testViewAllButton() { |
501 // Part 1: With "View All" action | 526 // Part 1: With "View All" action |
502 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); | 527 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); |
503 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); | 528 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); |
504 suggestionsSource.setInfoForCategory(TEST_CATEGORY, | 529 suggestionsSource.setInfoForCategory(TEST_CATEGORY, |
505 new CategoryInfoBuilder(TEST_CATEGORY) | 530 new CategoryInfoBuilder(TEST_CATEGORY) |
506 .withAction(ContentSuggestionsAdditionalAction.VIEW_ALL) | 531 .withAction(ContentSuggestionsAdditionalAction.VIEW_ALL) |
507 .showIfEmpty() | 532 .showIfEmpty() |
508 .build()); | 533 .build()); |
509 | 534 |
510 // 1.1 - Initial state. | 535 // 1.1 - Initial state. |
511 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | 536 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); |
512 reloadNtp(); | 537 reloadNtp(); |
513 assertItemsFor(sectionWithStatusCard().withActionButton().withProgress() ); | 538 assertItemsFor(sectionWithStatusCard().withViewAllButton().withProgress( )); |
514 | 539 |
515 // 1.2 - With suggestions. | 540 // 1.2 - With suggestions. |
516 List<SnippetArticle> suggestions = | 541 List<SnippetArticle> suggestions = |
517 Collections.unmodifiableList(createDummySuggestions(3, TEST_CATE GORY)); | 542 Collections.unmodifiableList(createDummySuggestions(3, TEST_CATE GORY)); |
518 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); | 543 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); |
519 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 544 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
520 assertItemsFor(section(3).withActionButton()); | 545 assertItemsFor(section(suggestions).withViewAllButton()); |
521 | 546 |
522 // 1.3 - When all suggestions are dismissed. | 547 // 1.3 - When all suggestions are dismissed. |
523 SuggestionsSection section = | 548 SuggestionsSection section = |
524 mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CA TEGORY); | 549 mAdapter.getSectionListForTesting().getSectionForTesting(TEST_CA TEGORY); |
525 assertSectionMatches(section(3).withActionButton(), section); | 550 assertSectionMatches(section(suggestions).withViewAllButton(), section); |
526 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); | 551 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); |
527 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); | 552 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); |
528 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); | 553 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); |
529 assertItemsFor(sectionWithStatusCard().withActionButton()); | 554 assertItemsFor(sectionWithStatusCard().withViewAllButton()); |
530 | 555 |
531 // Part 1: Without "View All" action | 556 // Part 1: Without "View All" action |
532 suggestionsSource = new FakeSuggestionsSource(); | 557 suggestionsSource = new FakeSuggestionsSource(); |
533 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); | 558 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.INI TIALIZING); |
534 suggestionsSource.setInfoForCategory( | 559 suggestionsSource.setInfoForCategory( |
535 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpt y().build()); | 560 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpt y().build()); |
536 | 561 |
537 // 2.1 - Initial state. | 562 // 2.1 - Initial state. |
538 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | 563 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); |
539 reloadNtp(); | 564 reloadNtp(); |
540 assertItemsFor(sectionWithStatusCard().withProgress()); | 565 assertItemsFor(sectionWithStatusCard().withProgress()); |
541 | 566 |
542 // 2.2 - With suggestions. | 567 // 2.2 - With suggestions. |
543 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); | 568 suggestionsSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVA ILABLE); |
544 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 569 suggestionsSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
545 assertItemsFor(section(3)); | 570 assertItemsFor(section(suggestions)); |
546 | 571 |
547 // 2.3 - When all suggestions are dismissed. | 572 // 2.3 - When all suggestions are dismissed. |
548 section = mAdapter.getSectionListForTesting().getSectionForTesting(TEST_ CATEGORY); | 573 section = mAdapter.getSectionListForTesting().getSectionForTesting(TEST_ CATEGORY); |
549 assertSectionMatches(section(3), section); | 574 assertSectionMatches(section(suggestions), section); |
550 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); | 575 section.removeSuggestionById(suggestions.get(0).mIdWithinCategory); |
551 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); | 576 section.removeSuggestionById(suggestions.get(1).mIdWithinCategory); |
552 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); | 577 section.removeSuggestionById(suggestions.get(2).mIdWithinCategory); |
553 assertItemsFor(sectionWithStatusCard()); | 578 assertItemsFor(sectionWithStatusCard()); |
554 } | 579 } |
555 | 580 |
556 /** | 581 /** |
582 * Tests that the more button is shown for sections that declare it. | |
583 */ | |
584 @Test | |
585 @Feature({"Ntp"}) | |
586 public void testFetchButton() { | |
587 @CategoryInt | |
588 final int category = 42; | |
dgn
2017/05/22 13:47:03
nit: use TEST_CATEGORY
Bernhard Bauer
2017/05/23 16:40:26
Done.
| |
589 | |
590 // Part 1: With "Fetch more" action | |
591 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); | |
592 suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALI ZING); | |
593 suggestionsSource.setInfoForCategory(category, | |
594 new CategoryInfoBuilder(category) | |
595 .withAction(ContentSuggestionsAdditionalAction.FETCH) | |
596 .showIfEmpty() | |
597 .build()); | |
598 | |
599 // 1.1 - Initial state. | |
600 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | |
601 reloadNtp(); | |
602 assertItemsFor(sectionWithStatusCard().withFetchButton().withProgress()) ; | |
603 | |
604 // 1.2 - With suggestions. | |
605 List<SnippetArticle> articles = | |
606 Collections.unmodifiableList(createDummySuggestions(3, category) ); | |
607 suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABL E); | |
608 suggestionsSource.setSuggestionsForCategory(category, articles); | |
609 assertItemsFor(section(articles).withFetchButton()); | |
610 | |
611 // 1.3 - When all suggestions are dismissed. | |
612 SuggestionsSection section42 = | |
613 mAdapter.getSectionListForTesting().getSectionForTesting(categor y); | |
614 assertSectionMatches(section(articles).withFetchButton(), section42); | |
615 section42.removeSuggestionById(articles.get(0).mIdWithinCategory); | |
616 section42.removeSuggestionById(articles.get(1).mIdWithinCategory); | |
617 section42.removeSuggestionById(articles.get(2).mIdWithinCategory); | |
618 assertItemsFor(sectionWithStatusCard().withFetchButton()); | |
619 | |
620 // Part 1: Without "Fetch more" action | |
621 suggestionsSource = new FakeSuggestionsSource(); | |
622 suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALI ZING); | |
623 suggestionsSource.setInfoForCategory( | |
624 category, new CategoryInfoBuilder(category).showIfEmpty().build( )); | |
625 | |
626 // 2.1 - Initial state. | |
627 when(mUiDelegate.getSuggestionsSource()).thenReturn(suggestionsSource); | |
628 reloadNtp(); | |
629 assertItemsFor(sectionWithStatusCard().withProgress()); | |
630 | |
631 // 2.2 - With suggestions. | |
632 suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABL E); | |
633 suggestionsSource.setSuggestionsForCategory(category, articles); | |
634 assertItemsFor(section(articles)); | |
635 | |
636 // 2.3 - When all suggestions are dismissed. | |
637 section42 = mAdapter.getSectionListForTesting().getSectionForTesting(cat egory); | |
638 assertSectionMatches(section(articles), section42); | |
639 section42.removeSuggestionById(articles.get(0).mIdWithinCategory); | |
640 section42.removeSuggestionById(articles.get(1).mIdWithinCategory); | |
641 section42.removeSuggestionById(articles.get(2).mIdWithinCategory); | |
642 assertItemsFor(sectionWithStatusCard()); | |
643 } | |
644 | |
645 /** | |
557 * Tests that invalidated suggestions are immediately removed. | 646 * Tests that invalidated suggestions are immediately removed. |
558 */ | 647 */ |
559 @Test | 648 @Test |
560 @Feature({"Ntp"}) | 649 @Feature({"Ntp"}) |
561 public void testSuggestionInvalidated() { | 650 public void testSuggestionInvalidated() { |
562 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); | 651 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); |
563 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 652 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
564 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 653 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
565 assertItemsFor(section(3)); | 654 assertItemsFor(section(suggestions)); |
566 assertArticlesEqual(suggestions, 2, 5); | |
567 | 655 |
568 SnippetArticle removed = suggestions.remove(1); | 656 SnippetArticle removed = suggestions.remove(1); |
569 mSource.fireSuggestionInvalidated(TEST_CATEGORY, removed.mIdWithinCatego ry); | 657 mSource.fireSuggestionInvalidated(TEST_CATEGORY, removed.mIdWithinCatego ry); |
570 assertArticlesEqual(suggestions, 2, 4); | 658 assertItemsFor(section(suggestions)); |
571 } | 659 } |
572 | 660 |
573 /** | 661 /** |
574 * Tests that the UI handles dynamically added (server-side) categories corr ectly. | 662 * Tests that the UI handles dynamically added (server-side) categories corr ectly. |
575 */ | 663 */ |
576 @Test | 664 @Test |
577 @Feature({"Ntp"}) | 665 @Feature({"Ntp"}) |
578 public void testDynamicCategories() { | 666 public void testDynamicCategories() { |
579 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); | 667 List<SnippetArticle> suggestions = createDummySuggestions(3, TEST_CATEGO RY); |
580 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); | 668 mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); |
581 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); | 669 mSource.setSuggestionsForCategory(TEST_CATEGORY, suggestions); |
582 assertItemsFor(section(3)); | 670 assertItemsFor(section(suggestions)); |
583 | 671 |
584 int dynamicCategory1 = 1010; | 672 int dynamicCategory1 = 1010; |
585 List<SnippetArticle> dynamics1 = createDummySuggestions(5, dynamicCatego ry1); | 673 List<SnippetArticle> dynamics1 = createDummySuggestions(5, dynamicCatego ry1); |
586 mSource.setInfoForCategory(dynamicCategory1, | 674 mSource.setInfoForCategory(dynamicCategory1, |
587 new CategoryInfoBuilder(dynamicCategory1) | 675 new CategoryInfoBuilder(dynamicCategory1) |
588 .withAction(ContentSuggestionsAdditionalAction.VIEW_ALL) | 676 .withAction(ContentSuggestionsAdditionalAction.VIEW_ALL) |
589 .build()); | 677 .build()); |
590 mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE) ; | 678 mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE) ; |
591 mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1); | 679 mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1); |
592 reloadNtp(); | 680 reloadNtp(); |
593 | 681 |
594 assertItemsFor(section(3), section(5).withActionButton()); | 682 assertItemsFor(section(suggestions), section(dynamics1).withViewAllButto n()); |
595 | 683 |
596 int dynamicCategory2 = 1011; | 684 int dynamicCategory2 = 1011; |
597 List<SnippetArticle> dynamics2 = createDummySuggestions(11, dynamicCateg ory2); | 685 List<SnippetArticle> dynamics2 = createDummySuggestions(11, dynamicCateg ory2); |
598 mSource.setInfoForCategory(dynamicCategory2, | 686 mSource.setInfoForCategory(dynamicCategory2, |
599 new CategoryInfoBuilder(dynamicCategory1).build()); | 687 new CategoryInfoBuilder(dynamicCategory1).build()); |
600 mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE) ; | 688 mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE) ; |
601 mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2); | 689 mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2); |
602 reloadNtp(); | 690 reloadNtp(); |
603 assertItemsFor(section(3), section(5).withActionButton(), section(11)); | 691 assertItemsFor( |
692 section(suggestions), section(dynamics1).withViewAllButton(), se ction(dynamics2)); | |
604 } | 693 } |
605 | 694 |
606 /** | 695 /** |
607 * Tests that the order of the categories is kept. | 696 * Tests that the order of the categories is kept. |
608 */ | 697 */ |
609 @Test | 698 @Test |
610 @Feature({"Ntp"}) | 699 @Feature({"Ntp"}) |
611 public void testCategoryOrder() { | 700 public void testCategoryOrder() { |
612 int[] categories = {TEST_CATEGORY, TEST_CATEGORY + 2, TEST_CATEGORY + 3, TEST_CATEGORY + 4}; | 701 int[] categories = {TEST_CATEGORY, TEST_CATEGORY + 2, TEST_CATEGORY + 3, TEST_CATEGORY + 4}; |
613 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); | 702 FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
953 } | 1042 } |
954 | 1043 |
955 /** | 1044 /** |
956 * Asserts that the given {@link TreeNode} is a {@link SuggestionsSection} t hat matches the | 1045 * Asserts that the given {@link TreeNode} is a {@link SuggestionsSection} t hat matches the |
957 * given {@link SectionDescriptor}. | 1046 * given {@link SectionDescriptor}. |
958 * @param descriptor The section descriptor to match against. | 1047 * @param descriptor The section descriptor to match against. |
959 * @param section The section from the adapter. | 1048 * @param section The section from the adapter. |
960 */ | 1049 */ |
961 private void assertSectionMatches(SectionDescriptor descriptor, SuggestionsS ection section) { | 1050 private void assertSectionMatches(SectionDescriptor descriptor, SuggestionsS ection section) { |
962 ItemsMatcher matcher = new ItemsMatcher(section); | 1051 ItemsMatcher matcher = new ItemsMatcher(section); |
963 matcher.expect(descriptor); | 1052 matcher.expectSection(descriptor); |
964 matcher.expectEnd(); | 1053 matcher.expectEnd(); |
965 } | 1054 } |
966 | 1055 |
967 /** | 1056 /** |
968 * Asserts that {@link #mAdapter}.{@link NewTabPageAdapter#getItemCount()} c orresponds to an NTP | 1057 * Asserts that {@link #mAdapter}.{@link NewTabPageAdapter#getItemCount()} c orresponds to an NTP |
969 * with the given sections in it. | 1058 * with the given sections in it. |
970 * | 1059 * |
971 * @param descriptors A list of descriptors, each describing a section that should be present on | 1060 * @param descriptors A list of descriptors, each describing a section that should be present on |
972 * the UI. | 1061 * the UI. |
973 */ | 1062 */ |
974 private void assertItemsFor(SectionDescriptor... descriptors) { | 1063 private void assertItemsFor(SectionDescriptor... descriptors) { |
975 ItemsMatcher matcher = new ItemsMatcher(mAdapter.getRootForTesting()); | 1064 ItemsMatcher matcher = new ItemsMatcher(mAdapter.getRootForTesting()); |
976 matcher.expect(ItemViewType.ABOVE_THE_FOLD); | 1065 matcher.expectAboveTheFoldItem(); |
977 for (SectionDescriptor descriptor : descriptors) matcher.expect(descript or); | 1066 for (SectionDescriptor descriptor : descriptors) matcher.expectSection(d escriptor); |
978 if (descriptors.length == 0) { | 1067 if (descriptors.length == 0) { |
979 matcher.expect(ItemViewType.ALL_DISMISSED); | 1068 matcher.expectAllDismissedItem(); |
980 } else { | 1069 } else { |
981 matcher.expect(ItemViewType.FOOTER); | 1070 matcher.expectFooter(); |
982 } | 1071 } |
983 matcher.expect(ItemViewType.SPACING); | 1072 matcher.expectSpacingItem(); |
984 matcher.expectEnd(); | 1073 matcher.expectEnd(); |
985 } | 1074 } |
986 | 1075 |
987 /** | 1076 /** |
988 * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a sect ion with | 1077 * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a sect ion with |
989 * {@code numSuggestions} cards in it. | 1078 * {@code numSuggestions} cards in it. |
990 * @param numSuggestions The number of suggestions in the section. If there are zero, use either | 1079 * @param suggestions The list of suggestions in the section. If the list is empty, use either |
991 * no section at all (if it is not displayed) or | 1080 * no section at all (if it is not displayed) or |
992 * {@link #sectionWithStatusCard()}. | 1081 * {@link #sectionWithStatusCard()}. |
993 * @return A descriptor for the section. | 1082 * @return A descriptor for the section. |
994 */ | 1083 */ |
995 private SectionDescriptor section(int numSuggestions) { | 1084 private SectionDescriptor section(List<SnippetArticle> suggestions) { |
996 assert numSuggestions > 0; | 1085 assert !suggestions.isEmpty(); |
997 return new SectionDescriptor(numSuggestions); | 1086 return new SectionDescriptor(suggestions); |
998 } | 1087 } |
999 | 1088 |
1000 /** | 1089 /** |
1001 * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a sect ion that has no | 1090 * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a sect ion that has no |
1002 * suggestions, but a status card to be displayed. | 1091 * suggestions, but a status card to be displayed. |
1003 * @return A descriptor for the section. | 1092 * @return A descriptor for the section. |
1004 */ | 1093 */ |
1005 private SectionDescriptor sectionWithStatusCard() { | 1094 private SectionDescriptor sectionWithStatusCard() { |
1006 return new SectionDescriptor(0); | 1095 return new SectionDescriptor(Collections.<SnippetArticle>emptyList()); |
1007 } | 1096 } |
1008 | 1097 |
1009 private void reloadNtp() { | 1098 private void reloadNtp() { |
1010 mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), makeUiCo nfig(), | 1099 mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), makeUiCo nfig(), |
1011 mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroup Delegate = | 1100 mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroup Delegate = |
1012 */ null); | 1101 */ null); |
1013 mAdapter.refreshSuggestions(); | 1102 mAdapter.refreshSuggestions(); |
1014 } | 1103 } |
1015 | 1104 |
1016 private void assertArticlesEqual(List<SnippetArticle> articles, int start, i nt end) { | |
1017 assertThat(mAdapter.getItemCount(), greaterThanOrEqualTo(end)); | |
1018 for (int i = start; i < end; i++) { | |
1019 assertEquals(articles.get(i - start), mAdapter.getSuggestionAt(i)); | |
1020 } | |
1021 } | |
1022 | |
1023 private boolean isSignInPromoVisible() { | 1105 private boolean isSignInPromoVisible() { |
1024 return mAdapter.getFirstPositionForType(ItemViewType.PROMO) != RecyclerV iew.NO_POSITION; | 1106 return mAdapter.getFirstPositionForType(ItemViewType.PROMO) != RecyclerV iew.NO_POSITION; |
1025 } | 1107 } |
1026 | 1108 |
1027 private int getCategory(TreeNode item) { | 1109 private int getCategory(TreeNode item) { |
1028 return ((SuggestionsSection) item).getCategory(); | 1110 return ((SuggestionsSection) item).getCategory(); |
1029 } | 1111 } |
1030 } | 1112 } |
OLD | NEW |