Commit 2805e633 authored by Theresa's avatar Theresa Committed by Commit Bot

[EoC] Add a simple integration test

Adds some testing foundation and one simple integration test.

BUG=827348

Change-Id: I71034071d32307dd922bc1a10f62e0bf1af070d0
Reviewed-on: https://chromium-review.googlesource.com/1007314
Commit-Queue: Theresa <twellington@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550000}
parent 0142b7fd
...@@ -2363,4 +2363,9 @@ public abstract class ChromeActivity extends AsyncInitializationActivity ...@@ -2363,4 +2363,9 @@ public abstract class ChromeActivity extends AsyncInitializationActivity
public float getLastActiveDensity() { public float getLastActiveDensity() {
return mDensityDpi; return mDensityDpi;
} }
@VisibleForTesting
public ContextualSuggestionsCoordinator getContextualSuggestionsCoordinatorForTesting() {
return mContextualSuggestionsCoordinator;
}
} }
...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.contextual_suggestions; ...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.contextual_suggestions;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate; import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
...@@ -165,4 +166,14 @@ public class ContextualSuggestionsCoordinator { ...@@ -165,4 +166,14 @@ public class ContextualSuggestionsCoordinator {
mBottomSheetContent = null; mBottomSheetContent = null;
} }
} }
@VisibleForTesting
ContextualSuggestionsMediator getMediatorForTesting() {
return mMediator;
}
@VisibleForTesting
ContextualSuggestionsModel getModelForTesting() {
return mModel;
}
} }
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor.Observer;
import org.chromium.chrome.browser.contextual_suggestions.FetchHelper.Delegate;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
/**
* Provides an injection mechanism for dependencies of the contextual_suggestions package.
*
* This class is intended to handle creating the instances of the various classes that interact with
* native code, so that they can be easily swapped out during tests.
*/
class ContextualSuggestionsDependencyFactory {
private static ContextualSuggestionsDependencyFactory sInstance;
static ContextualSuggestionsDependencyFactory getInstance() {
ThreadUtils.assertOnUiThread();
if (sInstance == null) sInstance = new ContextualSuggestionsDependencyFactory();
return sInstance;
}
@VisibleForTesting
static void setInstanceForTesting(ContextualSuggestionsDependencyFactory testInstance) {
if (sInstance != null && testInstance != null) {
throw new IllegalStateException("A real instance already exists.");
}
sInstance = testInstance;
}
/**
* @param profile Profile of the user.
* @return A {@link ContextualSuggestionsSource} for getting contextual suggestions for
* the current user.
*/
ContextualSuggestionsSource createContextualSuggestionSource(Profile profile) {
return new ContextualSuggestionsSource(profile);
}
/**
* @param observer The {@link Observer} to be notified of changes to enabled state.
* @return An {@link EnabledStateMonitor}.
*/
EnabledStateMonitor createEnabledStateMonitor(EnabledStateMonitor.Observer observer) {
return new EnabledStateMonitor(observer);
}
/**
* @param delegate The {@link Delegate} used to fetch suggestions.
* @param tabModelSelector The {@link TabModelSelector} for the containing Activity.
* @return A {@link FetchHelper}.
*/
FetchHelper createFetchHelper(Delegate delegate, TabModelSelector tabModelSelector) {
return new FetchHelper(delegate, tabModelSelector);
}
}
...@@ -44,8 +44,7 @@ class ContextualSuggestionsEventReporter implements SuggestionsEventReporter { ...@@ -44,8 +44,7 @@ class ContextualSuggestionsEventReporter implements SuggestionsEventReporter {
int eventId = windowOpenDisposition == WindowOpenDisposition.SAVE_TO_DISK int eventId = windowOpenDisposition == WindowOpenDisposition.SAVE_TO_DISK
? ContextualSuggestionsEvent.SUGGESTION_DOWNLOADED ? ContextualSuggestionsEvent.SUGGESTION_DOWNLOADED
: ContextualSuggestionsEvent.SUGGESTION_CLICKED; : ContextualSuggestionsEvent.SUGGESTION_CLICKED;
mSuggestionSource.getBridge().reportEvent( mSuggestionSource.reportEvent(mTabModelSelector.getCurrentTab().getWebContents(), eventId);
mTabModelSelector.getCurrentTab().getWebContents(), eventId);
} }
@Override @Override
......
...@@ -8,6 +8,7 @@ import android.support.annotation.Nullable; ...@@ -8,6 +8,7 @@ import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
...@@ -72,7 +73,9 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -72,7 +73,9 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
// Create a state monitor that will alert this mediator if the enabled state for contextual // Create a state monitor that will alert this mediator if the enabled state for contextual
// suggestions changes. // suggestions changes.
mEnabledStateMonitor = new EnabledStateMonitor(this); mEnabledStateMonitor =
ContextualSuggestionsDependencyFactory.getInstance().createEnabledStateMonitor(
this);
fullscreenManager.addListener(new FullscreenListener() { fullscreenManager.addListener(new FullscreenListener() {
@Override @Override
...@@ -131,8 +134,10 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -131,8 +134,10 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
@Override @Override
public void onEnabledStateChanged(boolean enabled) { public void onEnabledStateChanged(boolean enabled) {
if (enabled) { if (enabled) {
mSuggestionsSource = new ContextualSuggestionsSource(mProfile); mSuggestionsSource = ContextualSuggestionsDependencyFactory.getInstance()
mFetchHelper = new FetchHelper(this, mTabModelSelector); .createContextualSuggestionSource(mProfile);
mFetchHelper = ContextualSuggestionsDependencyFactory.getInstance().createFetchHelper(
this, mTabModelSelector);
} else { } else {
clearSuggestions(); clearSuggestions();
...@@ -151,7 +156,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -151,7 +156,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
@Override @Override
public void requestSuggestions(String url) { public void requestSuggestions(String url) {
mCurrentRequestUrl = url; mCurrentRequestUrl = url;
mSuggestionsSource.getBridge().fetchSuggestions(url, (suggestionsResult) -> { mSuggestionsSource.fetchSuggestions(url, (suggestionsResult) -> {
if (mSuggestionsSource == null) return; if (mSuggestionsSource == null) return;
// Avoiding double fetches causing suggestions for incorrect context. // Avoiding double fetches causing suggestions for incorrect context.
...@@ -190,7 +195,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -190,7 +195,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
mCoordinator.removeSuggestions(); mCoordinator.removeSuggestions();
mCurrentRequestUrl = ""; mCurrentRequestUrl = "";
if (mSuggestionsSource != null) mSuggestionsSource.getBridge().clearState(); if (mSuggestionsSource != null) mSuggestionsSource.clearState();
if (mSheetObserver != null) { if (mSheetObserver != null) {
mCoordinator.removeBottomSheetObserver(mSheetObserver); mCoordinator.removeBottomSheetObserver(mSheetObserver);
...@@ -277,8 +282,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -277,8 +282,7 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
} }
private void reportEvent(@ContextualSuggestionsEvent int event) { private void reportEvent(@ContextualSuggestionsEvent int event) {
mSuggestionsSource.getBridge().reportEvent( mSuggestionsSource.reportEvent(mTabModelSelector.getCurrentTab().getWebContents(), event);
mTabModelSelector.getCurrentTab().getWebContents(), event);
} }
private ClusterList generateClusterList(List<ContextualSuggestionsCluster> clusters) { private ClusterList generateClusterList(List<ContextualSuggestionsCluster> clusters) {
...@@ -288,4 +292,9 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet ...@@ -288,4 +292,9 @@ class ContextualSuggestionsMediator implements EnabledStateMonitor.Observer, Fet
return new ClusterList(clusters); return new ClusterList(clusters);
} }
@VisibleForTesting
void showContentInSheetForTesting() {
showContentInSheet();
}
} }
...@@ -7,10 +7,12 @@ package org.chromium.chrome.browser.contextual_suggestions; ...@@ -7,10 +7,12 @@ package org.chromium.chrome.browser.contextual_suggestions;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsBridge.ContextualSuggestionsResult;
import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.content_public.browser.WebContents;
import java.util.List; import java.util.List;
...@@ -18,7 +20,7 @@ import java.util.List; ...@@ -18,7 +20,7 @@ import java.util.List;
* Provides content for contextual suggestions. * Provides content for contextual suggestions.
*/ */
class ContextualSuggestionsSource implements SuggestionsSource { class ContextualSuggestionsSource implements SuggestionsSource {
private final ContextualSuggestionsBridge mBridge; private ContextualSuggestionsBridge mBridge;
/** /**
* Creates a ContextualSuggestionsSource for getting contextual suggestions for the current * Creates a ContextualSuggestionsSource for getting contextual suggestions for the current
...@@ -27,6 +29,14 @@ class ContextualSuggestionsSource implements SuggestionsSource { ...@@ -27,6 +29,14 @@ class ContextualSuggestionsSource implements SuggestionsSource {
* @param profile Profile of the user. * @param profile Profile of the user.
*/ */
ContextualSuggestionsSource(Profile profile) { ContextualSuggestionsSource(Profile profile) {
init(profile);
}
/**
* Initializes the ContextualSuggestionsSource. Intended to encapsulate creating connections
* to native code, so that this can be easily stubbed out during tests.
*/
protected void init(Profile profile) {
mBridge = new ContextualSuggestionsBridge(profile); mBridge = new ContextualSuggestionsBridge(profile);
} }
...@@ -53,11 +63,27 @@ class ContextualSuggestionsSource implements SuggestionsSource { ...@@ -53,11 +63,27 @@ class ContextualSuggestionsSource implements SuggestionsSource {
} }
/** /**
* @return The {@link ContextualSuggestionsBridge} used communicate with the contextual * Fetches suggestions for a given URL.
* suggestions C++ component. * @param url URL for which to fetch suggestions.
* @param callback Callback used to return suggestions for a given URL.
*/ */
ContextualSuggestionsBridge getBridge() { void fetchSuggestions(String url, Callback<ContextualSuggestionsResult> callback) {
return mBridge; mBridge.fetchSuggestions(url, callback);
}
/**
* Reports an event happening in the context of the current URL.
*
* @param webContents Web contents with the document for which event is reported.
* @param eventId The Id of the reported event as a {@link ContextualSuggestionsEvent} integer.
*/
void reportEvent(WebContents webContents, @ContextualSuggestionsEvent int eventId) {
mBridge.reportEvent(webContents, eventId);
}
/** Requests the backend to clear state. */
void clearState() {
mBridge.clearState();
} }
// The following methods are not applicable to contextual suggestions. // The following methods are not applicable to contextual suggestions.
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.contextual_suggestions; package org.chromium.chrome.browser.contextual_suggestions;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.search_engines.TemplateUrlService; import org.chromium.chrome.browser.search_engines.TemplateUrlService;
import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver; import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.browser.signin.SigninManager;
...@@ -25,7 +26,8 @@ public class EnabledStateMonitor ...@@ -25,7 +26,8 @@ public class EnabledStateMonitor
void onEnabledStateChanged(boolean enabled); void onEnabledStateChanged(boolean enabled);
} }
private final Observer mObserver; @VisibleForTesting
protected Observer mObserver;
private boolean mEnabled; private boolean mEnabled;
/** /**
...@@ -34,6 +36,16 @@ public class EnabledStateMonitor ...@@ -34,6 +36,16 @@ public class EnabledStateMonitor
*/ */
EnabledStateMonitor(Observer observer) { EnabledStateMonitor(Observer observer) {
mObserver = observer; mObserver = observer;
init();
}
/**
* Initializes the EnabledStateMonitor. Intended to encapsulate creating connections to native
* code, so that this can be easily stubbed out during tests. This method should only be
* overridden for testing.
*/
@VisibleForTesting
protected void init() {
ProfileSyncService.get().addSyncStateChangedListener(this); ProfileSyncService.get().addSyncStateChangedListener(this);
SigninManager.get().addSignInStateObserver(this); SigninManager.get().addSignInStateObserver(this);
TemplateUrlService.getInstance().addObserver(this); TemplateUrlService.getInstance().addObserver(this);
......
...@@ -35,8 +35,8 @@ class FetchHelper { ...@@ -35,8 +35,8 @@ class FetchHelper {
} }
private final Delegate mDelegate; private final Delegate mDelegate;
private final TabModelSelectorTabModelObserver mTabModelObserver; private TabModelSelectorTabModelObserver mTabModelObserver;
private final TabObserver mTabObserver; private TabObserver mTabObserver;
@Nullable @Nullable
private Tab mLastTab; private Tab mLastTab;
...@@ -50,7 +50,14 @@ class FetchHelper { ...@@ -50,7 +50,14 @@ class FetchHelper {
*/ */
FetchHelper(Delegate delegate, TabModelSelector tabModelSelector) { FetchHelper(Delegate delegate, TabModelSelector tabModelSelector) {
mDelegate = delegate; mDelegate = delegate;
init(tabModelSelector);
}
/**
* Initializes the FetchHelper. Intended to encapsulate creating connections to native code,
* so that this can be easily stubbed out during tests.
*/
protected void init(TabModelSelector tabModelSelector) {
mTabObserver = new EmptyTabObserver() { mTabObserver = new EmptyTabObserver() {
@Override @Override
public void onUpdateUrl(Tab tab, String url) { public void onUpdateUrl(Tab tab, String url) {
......
...@@ -300,6 +300,7 @@ chrome_java_sources = [ ...@@ -300,6 +300,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCluster.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCluster.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsDependencyFactory.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsEventReporter.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsEventReporter.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java",
"java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java", "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java",
...@@ -1578,6 +1579,11 @@ chrome_test_java_sources = [ ...@@ -1578,6 +1579,11 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java", "javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java",
"javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java", "javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java",
"javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java", "javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java",
"javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsDependenciesRule.java",
"javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java",
"javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeContextualSuggestionsSource.java",
"javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeEnabledStateMonitor.java",
"javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeFetchHelper.java",
"javatests/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnableTest.java", "javatests/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnableTest.java",
"javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java", "javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java",
"javatests/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporterTest.java", "javatests/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporterTest.java",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
/**
* Rule that allows mocking native dependencies of the contextual_suggestions package.
*
* The Factory members to override should be set before the main test rule is called to initialize
* the test activity.
*
* @see ContextualSuggestionsDependencyFactory
*/
public class ContextualSuggestionsDependenciesRule extends TestWatcher {
private TestFactory mFactory;
public TestFactory getFactory() {
return mFactory;
}
public ContextualSuggestionsDependenciesRule(TestFactory factory) {
mFactory = factory;
}
public ContextualSuggestionsDependenciesRule() {
this(new TestFactory());
}
@Override
protected void starting(Description description) {
ContextualSuggestionsDependencyFactory.setInstanceForTesting(mFactory);
}
@Override
protected void finished(Description description) {
ContextualSuggestionsDependencyFactory.setInstanceForTesting(null);
}
/**
* ContextualSuggestionsDependencyFactory that exposes and allows modifying the instances to be
* injected.
*/
static class TestFactory extends ContextualSuggestionsDependencyFactory {
public ContextualSuggestionsSource suggestionsSource;
public EnabledStateMonitor enabledStateMonitor;
public FetchHelper fetchHelper;
@Override
ContextualSuggestionsSource createContextualSuggestionSource(Profile profile) {
if (suggestionsSource != null) return suggestionsSource;
return super.createContextualSuggestionSource(profile);
}
@Override
EnabledStateMonitor createEnabledStateMonitor(EnabledStateMonitor.Observer observer) {
if (enabledStateMonitor != null) return enabledStateMonitor;
return super.createEnabledStateMonitor(observer);
}
@Override
FetchHelper createFetchHelper(
FetchHelper.Delegate delegate, TabModelSelector tabModelSelector) {
if (fetchHelper != null) return fetchHelper;
return super.createFetchHelper(delegate, tabModelSelector);
}
}
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.ChromeModernDesign;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.test.util.UiRestriction;
/**
* Tests related to displaying contextual suggestions in a bottom sheet.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
@EnableFeatures(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_BOTTOM_SHEET)
@ChromeModernDesign.Enable
public class ContextualSuggestionsTest {
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@Rule
public ContextualSuggestionsDependenciesRule mContextualSuggestionsDeps =
new ContextualSuggestionsDependenciesRule();
@Rule
public TestRule mChromeModernDesignStateRule = new ChromeModernDesign.Processor();
@Rule
public TestRule mFeaturesProcessor = new Features.InstrumentationProcessor();
private static final String TEST_PAGE = "/chrome/test/data/android/navigate/simple.html";
private EmbeddedTestServer mTestServer;
private ContextualSuggestionsCoordinator mCoordinator;
private ContextualSuggestionsMediator mMediator;
private ContextualSuggestionsModel mModel;
private BottomSheet mBottomSheet;
@Before
public void setUp() throws Exception {
mContextualSuggestionsDeps.getFactory().suggestionsSource =
new FakeContextualSuggestionsSource();
mContextualSuggestionsDeps.getFactory().fetchHelper = new FakeFetchHelper();
FakeEnabledStateMonitor stateMonitor = new FakeEnabledStateMonitor();
mContextualSuggestionsDeps.getFactory().enabledStateMonitor = new FakeEnabledStateMonitor();
mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PAGE));
ThreadUtils.runOnUiThreadBlocking(() -> {
mCoordinator =
mActivityTestRule.getActivity().getContextualSuggestionsCoordinatorForTesting();
mMediator = mCoordinator.getMediatorForTesting();
mModel = mCoordinator.getModelForTesting();
stateMonitor.setObserver(mMediator);
});
mBottomSheet = mActivityTestRule.getActivity().getBottomSheet();
}
@After
public void tearDown() {
mTestServer.stopAndDestroyServer();
}
@Test
@MediumTest
@Feature({"ContextualSuggestions"})
public void testOpenContextualSuggestionsBottomSheet() {
assertEquals("Sheet should be hidden.", BottomSheet.SHEET_STATE_HIDDEN,
mBottomSheet.getSheetState());
assertTrue("Title text should be empty, but was " + mModel.getTitle(),
TextUtils.isEmpty(mModel.getTitle()));
assertEquals("Cluster list should be empty.", 0, mModel.getClusterList().getItemCount());
ThreadUtils.runOnUiThreadBlocking(
() -> mMediator.requestSuggestions("http://www.testurl.com"));
assertTrue("Bottom sheet should contain suggestions content",
mBottomSheet.getCurrentSheetContent()
instanceof ContextualSuggestionsBottomSheetContent);
assertEquals("Sheet should still be hidden.", BottomSheet.SHEET_STATE_HIDDEN,
mBottomSheet.getSheetState());
assertEquals("Title text should be set.",
FakeContextualSuggestionsSource.TEST_TOOLBAR_TITLE, mModel.getTitle());
assertEquals("Cluster list should be set.",
(int) FakeContextualSuggestionsSource.TOTAL_ITEM_COUNT,
mModel.getClusterList().getItemCount());
ContextualSuggestionsBottomSheetContent content =
(ContextualSuggestionsBottomSheetContent) mBottomSheet.getCurrentSheetContent();
RecyclerView recyclerView = (RecyclerView) content.getContentView();
assertEquals("RecyclerView should be empty.", 0, recyclerView.getChildCount());
ThreadUtils.runOnUiThreadBlocking(() -> {
mMediator.showContentInSheetForTesting();
mBottomSheet.endAnimations();
});
assertEquals("Sheet should be peeked.", BottomSheet.SHEET_STATE_PEEK,
mBottomSheet.getSheetState());
assertNull("RecyclerView should still be empty.", recyclerView.getAdapter());
ThreadUtils.runOnUiThreadBlocking(
() -> mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_FULL, false));
assertEquals("RecyclerView should have content.",
(int) FakeContextualSuggestionsSource.TOTAL_ITEM_COUNT,
recyclerView.getAdapter().getItemCount());
}
// TODO(twellington): Add more tests!
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
import android.graphics.Bitmap;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsBridge.ContextualSuggestionsResult;
import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils;
import org.chromium.content_public.browser.WebContents;
/**
* A fake {@link ContextualSuggestionsSource} for use in testing.
*/
public class FakeContextualSuggestionsSource extends ContextualSuggestionsSource {
final static String TEST_TOOLBAR_TITLE = "Test toolbar title";
final static Integer NUMBER_OF_CLUSTERS = 3;
final static Integer ARTICLES_PER_CLUSTER = 3;
// There should be 12 items in the cluster list - 3 articles and a title per cluster.
final static Integer TOTAL_ITEM_COUNT = 12;
FakeContextualSuggestionsSource() {
super(null);
}
@Override
protected void init(Profile profile) {
// Intentionally do nothing.
}
@Override
public void destroy() {
// Intentionally do nothing.
}
@Override
public void fetchSuggestionImage(SnippetArticle suggestion, Callback<Bitmap> callback) {}
@Override
public void fetchContextualSuggestionImage(
SnippetArticle suggestion, Callback<Bitmap> callback) {}
@Override
public void fetchSuggestionFavicon(SnippetArticle suggestion, int minimumSizePx,
int desiredSizePx, Callback<Bitmap> callback) {}
@Override
void fetchSuggestions(String url, Callback<ContextualSuggestionsResult> callback) {
callback.onResult(createDummyResults());
}
@Override
void reportEvent(WebContents webContents, @ContextualSuggestionsEvent int eventId) {}
@Override
void clearState() {}
private ContextualSuggestionsResult createDummyResults() {
ContextualSuggestionsResult result = new ContextualSuggestionsResult(TEST_TOOLBAR_TITLE);
for (int clusterCount = 0; clusterCount < NUMBER_OF_CLUSTERS; clusterCount++) {
ContextualSuggestionsCluster cluster =
new ContextualSuggestionsCluster("Cluster " + clusterCount);
for (int articleCount = 0; articleCount < ARTICLES_PER_CLUSTER; articleCount++) {
cluster.getSuggestions().add(ContentSuggestionsTestUtils.createDummySuggestion(
KnownCategories.CONTEXTUAL));
}
result.getClusters().add(cluster);
}
return result;
}
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
/**
* A fake {@link EnabledStateMonitor} for use in testing. To finish initializing, call
* {@link #setObserver(Observer)}.
*/
class FakeEnabledStateMonitor extends EnabledStateMonitor {
FakeEnabledStateMonitor() {
super(null);
}
@Override
protected void init() {
// Intentionally do nothing.
}
@Override
void destroy() {
// Intentionally do nothing.
}
/**
* Sets an observer for testing.
* @param observer The {@link Observer} to be notified of changes to enabled state.
*/
void setObserver(EnabledStateMonitor.Observer observer) {
mObserver = observer;
observer.onEnabledStateChanged(true);
}
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextual_suggestions;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
/**
* A fake {@link FetchHelper} for use in testing.
*/
public class FakeFetchHelper extends FetchHelper {
FakeFetchHelper() {
super(null, null);
}
@Override
protected void init(TabModelSelector tabModelSelector) {
// Intentionally do nothing.
}
@Override
void destroy() {
// Intentionally do nothing.
}
}
file://chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/OWNERS
\ 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