blob: f5db1d09b0fa21cf190dcea3dcfb94aa658c3081 [file] [log] [blame]
// Copyright 2021 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.signin;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.not;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.test.runner.lifecycle.Stage;
import android.widget.ProgressBar;
import androidx.test.filters.MediumTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.Callback;
import org.chromium.base.test.util.ApplicationTestUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.firstrun.FirstRunPageDelegate;
import org.chromium.chrome.browser.firstrun.PolicyLoadListener;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
import org.chromium.components.signin.ChildAccountStatus;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.signin.test.util.FakeAccountInfoService;
import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
/**
* Tests for the class {@link SigninFirstRunFragment}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class SigninFirstRunFragmentTest {
private static final String TEST_EMAIL1 = "test.account1@gmail.com";
private static final String FULL_NAME1 = "Test Account1";
private static final String GIVEN_NAME1 = "Account1";
private static final String TEST_EMAIL2 = "test.account2@gmail.com";
private static final String CHILD_EMAIL = "child.account@gmail.com";
private static final String CHILD_FULL_NAME = "Test Child";
/**
* This class is used to test {@link SigninFirstRunFragment}.
*/
public static class CustomSigninFirstRunFragment extends SigninFirstRunFragment {
private FirstRunPageDelegate mFirstRunPageDelegate;
private boolean mIsAdvanceToNextPageCalled;
@Override
public FirstRunPageDelegate getPageDelegate() {
return mFirstRunPageDelegate;
}
void setPageDelegate(FirstRunPageDelegate delegate) {
mFirstRunPageDelegate = delegate;
}
@Override
public void advanceToNextPage() {
super.advanceToNextPage();
mIsAdvanceToNextPageCalled = true;
}
}
private final FakeAccountManagerFacade mFakeAccountManagerFacade =
new FakeAccountManagerFacade() {
@Override
public void checkChildAccountStatus(
Account account, ChildAccountStatusListener listener) {
listener.onStatusReady(account.name.equals(CHILD_EMAIL)
? ChildAccountStatus.REGULAR_CHILD
: ChildAccountStatus.NOT_CHILD);
}
};
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final AccountManagerTestRule mAccountManagerTestRule =
new AccountManagerTestRule(mFakeAccountManagerFacade, new FakeAccountInfoService());
@Rule
public final ChromeTabbedActivityTestRule mChromeActivityTestRule =
new ChromeTabbedActivityTestRule();
@Mock
private FirstRunPageDelegate mFirstRunPageDelegateMock;
@Mock
private PolicyLoadListener mPolicyLoadListenerMock;
@Captor
private ArgumentCaptor<Callback<Boolean>> mCallbackCaptor;
private CustomSigninFirstRunFragment mFragment;
@Before
public void setUp() {
SigninCheckerProvider.setForTests(mock(SigninChecker.class));
when(mPolicyLoadListenerMock.get()).thenReturn(false);
when(mFirstRunPageDelegateMock.getPolicyLoadListener()).thenReturn(mPolicyLoadListenerMock);
mChromeActivityTestRule.startMainActivityOnBlankPage();
mFragment = new CustomSigninFirstRunFragment();
mFragment.setPageDelegate(mFirstRunPageDelegateMock);
}
@Test
@MediumTest
public void testFragmentWhenAddingAccountDynamically() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
launchActivityWithFragment();
Assert.assertFalse(
mFragment.getView().findViewById(R.id.signin_fre_selected_account).isShown());
onView(withText(R.string.signin_add_account_to_device)).check(matches(isDisplayed()));
onView(withText(R.string.signin_fre_dismiss_button)).check(matches(isDisplayed()));
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
checkFragmentWithSelectedAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1);
}
@Test
@MediumTest
public void testFragmentWithDefaultAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
launchActivityWithFragment();
checkFragmentWithSelectedAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1);
onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testFragmentWhenChoosingAnotherAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
mAccountManagerTestRule.addAccount(
TEST_EMAIL2, /* fullName= */ null, /* givenName= */ null, /* avatar= */ null);
launchActivityWithFragment();
onView(withText(TEST_EMAIL1)).perform(click());
onView(withText(TEST_EMAIL2)).inRoot(isDialog()).perform(click());
checkFragmentWithSelectedAccount(TEST_EMAIL2, /* fullName= */ null, /* givenName= */ null);
onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testFragmentWithDefaultAccountWhenPolicyAvailableOnDevice() {
when(mPolicyLoadListenerMock.get()).thenReturn(true);
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
launchActivityWithFragment();
checkFragmentWithSelectedAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1);
onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testFragmentWithSupervisedAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(
CHILD_EMAIL, CHILD_FULL_NAME, /* givenName= */ null, /* avatar= */ null);
launchActivityWithFragment();
onView(withText(R.string.fre_welcome)).check(matches(isDisplayed()));
Assert.assertFalse(
mFragment.getView().findViewById(R.id.signin_fre_selected_account).isEnabled());
onView(withText(CHILD_EMAIL)).check(matches(isDisplayed()));
onView(withText(CHILD_FULL_NAME)).check(matches(isDisplayed()));
final String continueAsText =
mFragment.getString(R.string.signin_promo_continue_as, CHILD_FULL_NAME);
onView(withText(continueAsText)).check(matches(isDisplayed()));
onView(withText(R.string.signin_fre_dismiss_button)).check(matches(not(isDisplayed())));
onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testSigninWithDefaultAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
launchActivityWithFragment();
final String continueAsText = mChromeActivityTestRule.getActivity().getString(
R.string.signin_promo_continue_as, GIVEN_NAME1);
onView(withText(continueAsText)).perform(click());
CriteriaHelper.pollUiThread(() -> {
return IdentityServicesProvider.get()
.getIdentityManager(Profile.getLastUsedRegularProfile())
.hasPrimaryAccount(ConsentLevel.SIGNIN);
});
final CoreAccountInfo primaryAccount =
mAccountManagerTestRule.getPrimaryAccount(ConsentLevel.SIGNIN);
Assert.assertEquals(TEST_EMAIL1, primaryAccount.getEmail());
}
@Test
@MediumTest
public void testContinueButtonWhenUserIsSignedIn() {
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
final CoreAccountInfo primaryAccount = mAccountManagerTestRule.addTestAccountThenSignin();
Assert.assertNotEquals("The primary account should be a different account!", TEST_EMAIL1,
primaryAccount.getEmail());
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
launchActivityWithFragment();
final String continueAsText = mChromeActivityTestRule.getActivity().getString(
R.string.signin_promo_continue_as, GIVEN_NAME1);
onView(withText(continueAsText)).perform(click());
CriteriaHelper.pollUiThread(() -> mFragment.mIsAdvanceToNextPageCalled);
final CoreAccountInfo currentPrimaryAccount =
TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
return IdentityServicesProvider.get()
.getIdentityManager(Profile.getLastUsedRegularProfile())
.getPrimaryAccountInfo(ConsentLevel.SIGNIN);
});
Assert.assertEquals(primaryAccount, currentPrimaryAccount);
verify(mFirstRunPageDelegateMock).acceptTermsOfService(true);
}
@Test
@MediumTest
public void testContinueButtonWithSupervisedAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(
CHILD_EMAIL, CHILD_FULL_NAME, /* givenName= */ null, /* avatar= */ null);
launchActivityWithFragment();
final String continueAsText = mChromeActivityTestRule.getActivity().getString(
R.string.signin_promo_continue_as, CHILD_FULL_NAME);
onView(withText(continueAsText)).perform(click());
CriteriaHelper.pollUiThread(() -> { return mFragment.mIsAdvanceToNextPageCalled; });
Assert.assertNull(mAccountManagerTestRule.getPrimaryAccount(ConsentLevel.SIGNIN));
verify(mFirstRunPageDelegateMock).acceptTermsOfService(true);
}
@Test
@MediumTest
public void testFragmentWhenAddingAnotherAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
launchActivityWithFragment();
onView(withText(TEST_EMAIL1)).perform(click());
onView(withText(R.string.signin_add_account_to_device)).perform(click());
Intent data = new Intent();
data.putExtra(AccountManager.KEY_ACCOUNT_NAME, TEST_EMAIL2);
TestThreadUtils.runOnUiThreadBlocking(
()
-> mFragment.onActivityResult(
SigninFirstRunFragment.ADD_ACCOUNT_REQUEST_CODE, Activity.RESULT_OK,
data));
checkFragmentWithSelectedAccount(TEST_EMAIL2, /* fullName= */ null, /* givenName= */ null);
}
@Test
@MediumTest
public void testFragmentWhenAddingDefaultAccount() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
launchActivityWithFragment();
onView(withText(R.string.signin_add_account_to_device)).perform(click());
Intent data = new Intent();
data.putExtra(AccountManager.KEY_ACCOUNT_NAME, TEST_EMAIL1);
TestThreadUtils.runOnUiThreadBlocking(
()
-> mFragment.onActivityResult(
SigninFirstRunFragment.ADD_ACCOUNT_REQUEST_CODE, Activity.RESULT_OK,
data));
checkFragmentWithSelectedAccount(TEST_EMAIL1, /* fullName= */ null, /* givenName= */ null);
}
@Test
@MediumTest
public void testFragmentWhenPolicyIsLoadedAfterNative() {
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
when(mPolicyLoadListenerMock.get()).thenReturn(null);
launchActivityWithFragment();
checkFragmentWhenLoadingNativeAndPolicyAndHideTheSpinner();
when(mPolicyLoadListenerMock.get()).thenReturn(false);
verify(mPolicyLoadListenerMock).onAvailable(mCallbackCaptor.capture());
TestThreadUtils.runOnUiThreadBlocking(
() -> { mCallbackCaptor.getValue().onResult(false); });
checkFragmentWithSelectedAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1);
}
@Test
@MediumTest
public void testFragmentWhenNativeIsLoadedAfterPolicy() {
mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
launchActivityWithFragment();
checkFragmentWhenLoadingNativeAndPolicyAndHideTheSpinner();
TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
checkFragmentWithSelectedAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1);
}
private void checkFragmentWithSelectedAccount(String email, String fullName, String givenName) {
CriteriaHelper.pollUiThread(
mFragment.getView().findViewById(R.id.signin_fre_selected_account)::isShown);
final DisplayableProfileData profileData =
new DisplayableProfileData(email, mock(Drawable.class), fullName, givenName);
onView(withText(R.string.fre_welcome)).check(matches(isDisplayed()));
onView(withText(email)).check(matches(isDisplayed()));
if (fullName != null) {
onView(withText(fullName)).check(matches(isDisplayed()));
}
final String continueAsText = mFragment.getString(
R.string.signin_promo_continue_as, profileData.getGivenNameOrFullNameOrEmail());
onView(withText(continueAsText)).check(matches(isDisplayed()));
onView(withText(R.string.signin_fre_dismiss_button)).check(matches(isDisplayed()));
onView(withId(R.id.signin_fre_footer)).check(matches(isDisplayed()));
}
private void checkFragmentWhenLoadingNativeAndPolicyAndHideTheSpinner() {
CriteriaHelper.pollUiThread(() -> {
return mFragment.getView().findViewById(R.id.signin_fre_progress_spinner).isShown();
});
TestThreadUtils.runOnUiThreadBlocking(() -> {
ProgressBar progressBar =
mFragment.getView().findViewById(R.id.signin_fre_progress_spinner);
// Replace the progress bar with a dummy to allow other checks. Currently the
// progress bar cannot be stopped otherwise due to some espresso issues (crbug/1115067).
progressBar.setIndeterminateDrawable(
new ColorDrawable(mFragment.getResources().getColor(R.color.default_bg_color)));
});
onView(withText(R.string.fre_welcome)).check(matches(isDisplayed()));
onView(withText(TEST_EMAIL1)).check(matches(not(isDisplayed())));
onView(withText(FULL_NAME1)).check(matches(not(isDisplayed())));
final String continueAsText = mChromeActivityTestRule.getActivity().getString(
R.string.signin_promo_continue_as, GIVEN_NAME1);
onView(withText(continueAsText)).check(matches(not(isDisplayed())));
onView(withText(R.string.signin_fre_dismiss_button)).check(matches(not(isDisplayed())));
onView(withId(R.id.signin_fre_footer)).check(matches(not(isDisplayed())));
verify(mPolicyLoadListenerMock).onAvailable(notNull());
}
private void launchActivityWithFragment() {
TestThreadUtils.runOnUiThreadBlocking(() -> {
mChromeActivityTestRule.getActivity()
.getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, mFragment)
.commit();
});
ApplicationTestUtils.waitForActivityState(
mChromeActivityTestRule.getActivity(), Stage.RESUMED);
}
}