blob: 330432bc3ea75c0dfe67824bec3d09c4f7329de0 [file] [log] [blame]
// Copyright 2020 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.browserservices;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.createSession;
import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.createTrustedWebActivityIntent;
import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.isTrustedWebActivity;
import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.spoofVerification;
import static org.chromium.chrome.browser.notifications.NotificationConstants.NOTIFICATION_ID_TWA_DISCLOSURE;
import android.content.Intent;
import android.support.test.espresso.Espresso;
import android.support.test.filters.MediumTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.chromium.base.ContextUtils;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
import org.chromium.chrome.browser.dependency_injection.ModuleOverridesRule;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.browser_ui.notifications.MockNotificationManagerProxy;
import org.chromium.components.browser_ui.notifications.MockNotificationManagerProxy.NotificationEntry;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxy;
import org.chromium.components.embedder_support.util.Origin;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.EmbeddedTestServerRule;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeoutException;
/**
* Instrumentation tests to make sure the Running in Chrome prompt is shown.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Features.EnableFeatures(ChromeFeatureList.TRUSTED_WEB_ACTIVITY_NEW_DISCLOSURE)
public class RunningInChromeTest {
private static final String TAG = "RunningInChrome";
private static final String TEST_PAGE = "/chrome/test/data/android/google.html";
private static final String PACKAGE_NAME =
ContextUtils.getApplicationContext().getPackageName();
private static final Set<Integer> TEST_SNACKBARS = new HashSet<>(Arrays.asList(
Snackbar.UMA_TWA_PRIVACY_DISCLOSURE, Snackbar.UMA_TWA_PRIVACY_DISCLOSURE_V2));
private final CustomTabActivityTestRule mCustomTabActivityTestRule =
new CustomTabActivityTestRule();
private final EmbeddedTestServerRule mEmbeddedTestServerRule = new EmbeddedTestServerRule();
private final TestRule mModuleOverridesRule = new ModuleOverridesRule()
.setOverride(ChromeActivityCommonsModule.Factory.class,
ChromeActivityCommonsModuleForTest::new);
@Rule
public RuleChain mRuleChain = RuleChain.emptyRuleChain()
.around(mCustomTabActivityTestRule)
.around(mEmbeddedTestServerRule)
.around(mModuleOverridesRule);
/**
* This class causes Dagger to provide our MockNotificationManagerProxy instead of the real one.
*/
class ChromeActivityCommonsModuleForTest extends ChromeActivityCommonsModule {
public ChromeActivityCommonsModuleForTest(ChromeActivity<?> activity,
ActivityLifecycleDispatcher lifecycleDispatcher) {
super(activity, lifecycleDispatcher);
}
@Override
public NotificationManagerProxy provideNotificationManagerProxy() {
return mMockNotificationManager;
}
}
private String mTestPage;
private BrowserServicesStore mStore;
private final MockNotificationManagerProxy mMockNotificationManager =
new MockNotificationManagerProxy();
@Before
public void setUp() {
// Native needs to be initialized to start the test server.
LibraryLoader.getInstance().ensureInitialized();
mEmbeddedTestServerRule.setServerUsesHttps(true); // TWAs only work with HTTPS.
mTestPage = mEmbeddedTestServerRule.getServer().getURL(TEST_PAGE);
mMockNotificationManager.setNotificationsEnabled(false);
mStore = new BrowserServicesStore(
ChromeApplication.getComponent().resolveSharedPreferencesManager());
mStore.removeTwaDisclosureAcceptanceForPackage(PACKAGE_NAME);
}
@Test
@MediumTest
@DisabledTest(message = "https://crbug.com/1072424")
@Features.DisableFeatures(ChromeFeatureList.TRUSTED_WEB_ACTIVITY_NEW_DISCLOSURE)
public void showsRunningInChrome() throws TimeoutException {
Intent intent = createTrustedWebActivityIntent(mTestPage);
launch(intent);
clearOtherSnackbars();
assertTrue(isTrustedWebActivity(mCustomTabActivityTestRule.getActivity()));
Espresso.onView(withText(containsString(getV1String())))
.check(matches(isDisplayed()));
}
@Test
@MediumTest
public void showsNewRunningInChrome() throws TimeoutException {
launch(createTrustedWebActivityIntent(mTestPage));
clearOtherSnackbars();
assertTrue(isTrustedWebActivity(mCustomTabActivityTestRule.getActivity()));
Espresso.onView(withText(containsString(getV1String())))
.check(doesNotExist());
String site = Origin.createOrThrow(mTestPage).toString();
Espresso.onView(withText(containsString(getV2String(site))))
.check(matches(isDisplayed()));
}
@Test
@MediumTest
public void showsNotification() throws TimeoutException {
mMockNotificationManager.setNotificationsEnabled(true);
launch(createTrustedWebActivityIntent(mTestPage));
String scope = Origin.createOrThrow(mTestPage).toString();
CriteriaHelper.pollUiThread(() ->
assertTrue(showingNotification(scope, NOTIFICATION_ID_TWA_DISCLOSURE)));
}
@Test
@MediumTest
public void dismissesNotification_onNavigation() throws TimeoutException {
mMockNotificationManager.setNotificationsEnabled(true);
launch(createTrustedWebActivityIntent(mTestPage));
String scope = Origin.createOrThrow(mTestPage).toString();
CriteriaHelper.pollUiThread(() ->
assertTrue(showingNotification(scope, NOTIFICATION_ID_TWA_DISCLOSURE)));
mCustomTabActivityTestRule.loadUrl("https://www.example.com/");
CriteriaHelper.pollUiThread(() ->
assertFalse(showingNotification(scope, NOTIFICATION_ID_TWA_DISCLOSURE)));
}
@Test
@MediumTest
public void dismissesNotification_onActivityClose() throws TimeoutException {
mMockNotificationManager.setNotificationsEnabled(true);
launch(createTrustedWebActivityIntent(mTestPage));
String scope = Origin.createOrThrow(mTestPage).toString();
CriteriaHelper.pollUiThread(() ->
assertTrue(showingNotification(scope, NOTIFICATION_ID_TWA_DISCLOSURE)));
mCustomTabActivityTestRule.getActivity().finish();
CriteriaHelper.pollUiThread(() ->
assertFalse(showingNotification(scope, NOTIFICATION_ID_TWA_DISCLOSURE)));
}
private boolean showingNotification(String tag, int id) {
for (NotificationEntry entry : mMockNotificationManager.getNotifications()) {
if (entry.tag.equals(tag) && entry.id == id) return true;
}
return false;
}
public void launch(Intent intent) throws TimeoutException {
String url = intent.getData().toString();
spoofVerification(PACKAGE_NAME, url);
createSession(intent, PACKAGE_NAME);
mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
}
private void clearOtherSnackbars() {
// On the trybots a Downloads Snackbar is shown over the one we want to test.
SnackbarManager manager = mCustomTabActivityTestRule.getActivity().getSnackbarManager();
TestThreadUtils.runOnUiThreadBlocking(() -> {
while (true) {
Snackbar snackbar = manager.getCurrentSnackbarForTesting();
if (snackbar == null) break;
if (TEST_SNACKBARS.contains(snackbar.getIdentifierForTesting())) break;
manager.dismissSnackbars(snackbar.getController());
}
});
}
private String getV2String(String scope) {
return mCustomTabActivityTestRule.getActivity().getResources()
.getString(R.string.twa_running_in_chrome_v2, scope);
}
private String getV1String() {
return mCustomTabActivityTestRule.getActivity().getResources()
.getString(R.string.twa_running_in_chrome);
}
}