[go: nahoru, domu]

blob: 60d15c1d2839617abb0ea28edaab91c0bb7b4337 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h"
#import "base/apple/foundation_util.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller_constants.h"
#import "ios/chrome/browser/signin/fake_system_identity.h"
#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_constants.h"
#import "ios/chrome/browser/ui/authentication/signin/signin_constants.h"
#import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
#import "ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h"
#import "ios/chrome/browser/ui/authentication/signin_matchers.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_constants.h"
#import "ios/chrome/browser/ui/authentication/views/views_constants.h"
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
#import "ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_constants.h"
#import "ios/chrome/browser/ui/settings/google_services/google_services_settings_constants.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_matchers_app_interface.h"
#import "ios/chrome/test/scoped_eg_synchronization_disabler.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ui/base/l10n/l10n_util_mac.h"
using chrome_test_util::ButtonWithAccessibilityLabel;
using chrome_test_util::PrimarySignInButton;
using chrome_test_util::SecondarySignInButton;
using chrome_test_util::SettingsAccountButton;
using chrome_test_util::SettingsDoneButton;
using chrome_test_util::SignOutAccountsButton;
using chrome_test_util::IdentityCellMatcherForEmail;
namespace {
// Closes the managed account dialog, if `fakeIdentity` is a managed account.
void CloseSigninManagedAccountDialogIfAny(FakeSystemIdentity* fakeIdentity) {
// Don't expect a managed account dialog when the account isn't considered
// managed.
if ([fakeIdentity.userEmail hasSuffix:@"@gmail.com"]) {
return;
}
// Synchronization off due to an infinite spinner, in the user consent view,
// under the managed consent dialog. This spinner is started by the sign-in
// process.
ScopedSynchronizationDisabler disabler;
id<GREYMatcher> acceptButton = [ChromeMatchersAppInterface
buttonWithAccessibilityLabelID:IDS_IOS_MANAGED_SIGNIN_ACCEPT_BUTTON];
[ChromeEarlGrey waitForMatcher:acceptButton];
[[EarlGrey selectElementWithMatcher:acceptButton] performAction:grey_tap()];
}
} // namespace
@implementation SigninEarlGreyUI
+ (void)signinWithFakeIdentity:(FakeSystemIdentity*)fakeIdentity {
[self signinWithFakeIdentity:fakeIdentity enableSync:YES];
}
+ (void)signinWithFakeIdentity:(FakeSystemIdentity*)fakeIdentity
enableSync:(BOOL)enableSync {
[SigninEarlGrey addFakeIdentity:fakeIdentity];
if (!enableSync) {
[ChromeEarlGrey signInWithoutSyncWithIdentity:fakeIdentity];
ConditionBlock condition = ^bool {
return [[SigninEarlGreyAppInterface primaryAccountGaiaID]
isEqualToString:fakeIdentity.gaiaID];
};
BOOL isSigned = base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, condition);
GREYAssert(
isSigned, @"Signed in failed. Expected: %@, Currently signed: %@",
fakeIdentity.gaiaID, [SigninEarlGreyAppInterface primaryAccountGaiaID]);
return;
}
[SigninEarlGreyUI tapPrimarySignInButtonInRecentTabs];
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kIdentityButtonControlIdentifier)]
performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:IdentityCellMatcherForEmail(
fakeIdentity.userEmail)]
performAction:grey_tap()];
[self tapSigninConfirmationDialog];
CloseSigninManagedAccountDialogIfAny(fakeIdentity);
[[[EarlGrey
selectElementWithMatcher:grey_allOf(
grey_accessibilityID(
kTableViewNavigationDismissButtonId),
grey_sufficientlyVisible(), nil)]
usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
onElementWithMatcher:
grey_allOf(grey_accessibilityID(
kRecentTabsTableViewControllerAccessibilityIdentifier),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
// Sync utilities require sync to be initialized in order to perform
// operations on the Sync server.
[ChromeEarlGrey waitForSyncEngineInitialized:YES
syncTimeout:base::Seconds(10)];
}
+ (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation {
int confirmationLabelID = 0;
switch (confirmation) {
case SignOutConfirmationChoiceClearData:
confirmationLabelID = IDS_IOS_SIGNOUT_DIALOG_CLEAR_DATA_BUTTON;
break;
case SignOutConfirmationChoiceKeepData:
confirmationLabelID = IDS_IOS_SIGNOUT_DIALOG_KEEP_DATA_BUTTON;
break;
case SignOutConfirmationChoiceNotSyncing:
confirmationLabelID = IDS_IOS_SIGNOUT_DIALOG_SIGN_OUT_BUTTON;
break;
}
[self signOutWithButton:SignOutAccountsButton()
confirmationLabelID:confirmationLabelID];
}
+ (void)tapSigninConfirmationDialog {
// To confirm the dialog, the scroll view content has to be scrolled to the
// bottom to transform "MORE" button into the validation button.
// EarlGrey fails to scroll to the bottom, using grey_scrollToContentEdge(),
// if the scroll view doesn't bounce and by default a scroll view doesn't
// bounce when the content fits into the scroll view (the scroll never ends).
// To test if the content fits into the scroll view,
// ContentViewSmallerThanScrollView() matcher is used on the signin scroll
// view.
// If the matcher fails, then the scroll view should be scrolled to the
// bottom.
// Once to the bottom, the consent can be confirmed.
[ChromeEarlGreyUI waitForAppToIdle];
id<GREYMatcher> confirmationScrollViewMatcher =
grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:confirmationScrollViewMatcher]
assertWithMatcher:chrome_test_util::ContentViewSmallerThanScrollView()
error:&error];
if (error) {
[[EarlGrey selectElementWithMatcher:confirmationScrollViewMatcher]
performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
}
id<GREYMatcher> buttonMatcher = [ChromeMatchersAppInterface
buttonWithAccessibilityLabelID:IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON];
[[EarlGrey selectElementWithMatcher:buttonMatcher] performAction:grey_tap()];
}
+ (void)tapAddAccountButton {
id<GREYMatcher> confirmationScrollViewMatcher =
grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
[ChromeEarlGreyUI waitForAppToIdle];
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:confirmationScrollViewMatcher]
assertWithMatcher:chrome_test_util::ContentViewSmallerThanScrollView()
error:&error];
if (error) {
// If the consent is bigger than the scroll view, the primary button should
// be "MORE".
[[EarlGrey selectElementWithMatcher:
chrome_test_util::ButtonWithAccessibilityLabelId(
IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SCROLL_BUTTON)]
assertWithMatcher:grey_notNil()];
[[EarlGrey selectElementWithMatcher:confirmationScrollViewMatcher]
performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
}
id<GREYMatcher> buttonMatcher = [ChromeMatchersAppInterface
buttonWithAccessibilityLabelID:
IDS_IOS_ACCOUNT_UNIFIED_CONSENT_ADD_ACCOUNT];
[[EarlGrey selectElementWithMatcher:buttonMatcher] performAction:grey_tap()];
}
+ (void)verifySigninPromoVisibleWithMode:(SigninPromoViewMode)mode {
[self verifySigninPromoVisibleWithMode:mode closeButton:YES];
}
+ (void)verifySigninPromoVisibleWithMode:(SigninPromoViewMode)mode
closeButton:(BOOL)closeButton {
[ChromeEarlGreyUI waitForAppToIdle];
[[EarlGrey
selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_notNil()];
switch (mode) {
case SigninPromoViewModeNoAccounts:
case SigninPromoViewModeSyncWithPrimaryAccount:
[[EarlGrey
selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_nil()];
break;
case SigninPromoViewModeSigninWithAccount:
// TODO(crbug.com/1210846): Determine when the SecondarySignInButton
// should be present and assert that.
break;
}
if (closeButton) {
[[EarlGrey
selectElementWithMatcher:grey_allOf(grey_accessibilityID(
kSigninPromoCloseButtonId),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_notNil()];
}
}
+ (void)verifySigninPromoNotVisible {
[[EarlGrey
selectElementWithMatcher:grey_allOf(
grey_accessibilityID(kSigninPromoViewId),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_nil()];
[[EarlGrey
selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
grey_sufficientlyVisible(), nil)]
assertWithMatcher:grey_nil()];
}
+ (void)openRemoveAccountConfirmationDialogWithFakeIdentity:
(FakeSystemIdentity*)fakeIdentity {
[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(
fakeIdentity.userEmail)]
performAction:grey_tap()];
[[EarlGrey
selectElementWithMatcher:ButtonWithAccessibilityLabel(
l10n_util::GetNSString(
IDS_IOS_REMOVE_GOOGLE_ACCOUNT_TITLE))]
performAction:grey_tap()];
}
+ (void)openMyGoogleDialogWithFakeIdentity:(FakeSystemIdentity*)fakeIdentity {
[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(
fakeIdentity.userEmail)]
performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:
ButtonWithAccessibilityLabel(l10n_util::GetNSString(
IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE))]
performAction:grey_tap()];
[ChromeEarlGreyUI waitForAppToIdle];
}
+ (void)tapRemoveAccountFromDeviceWithFakeIdentity:
(FakeSystemIdentity*)fakeIdentity {
[self openRemoveAccountConfirmationDialogWithFakeIdentity:fakeIdentity];
[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(
l10n_util::GetNSString(
IDS_IOS_REMOVE_ACCOUNT_LABEL))]
performAction:grey_tap()];
// Wait until the account is removed.
[ChromeEarlGreyUI waitForAppToIdle];
}
+ (void)tapPrimarySignInButtonInRecentTabs {
[ChromeEarlGreyUI openToolsMenu];
[ChromeEarlGreyUI
tapToolsMenuButton:chrome_test_util::RecentTabsDestinationButton()];
[[[EarlGrey
selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
grey_sufficientlyVisible(), nil)]
usingSearchAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)
onElementWithMatcher:
grey_allOf(grey_accessibilityID(
kRecentTabsTableViewControllerAccessibilityIdentifier),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
}
+ (void)tapPrimarySignInButtonInTabSwitcher {
[ChromeEarlGreyUI openTabGrid];
[[EarlGrey selectElementWithMatcher:chrome_test_util::
TabGridOtherDevicesPanelButton()]
performAction:grey_tap()];
// The start point needs to avoid the "Done" bar on iPhone, in order to catch
// the table view and scroll.
[[[EarlGrey
selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
grey_sufficientlyVisible(), nil)]
usingSearchAction:grey_scrollToContentEdgeWithStartPoint(
kGREYContentEdgeBottom, 0.5, 0.5)
onElementWithMatcher:
grey_allOf(grey_accessibilityID(
kRecentTabsTableViewControllerAccessibilityIdentifier),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
}
+ (void)verifyWebSigninIsVisible:(BOOL)isVisible {
NSString* conditionDescription = isVisible
? @"Web sign-in should be visible"
: @"Web sign-in should not be visible";
id<GREYMatcher> matcher =
isVisible ? grey_sufficientlyVisible() : grey_notVisible();
GREYCondition* condition = [GREYCondition
conditionWithName:conditionDescription
block:^BOOL {
NSError* error;
[[EarlGrey selectElementWithMatcher:
grey_accessibilityID(
kWebSigninAccessibilityIdentifier)]
assertWithMatcher:matcher
error:&error];
return error == nil;
}];
GREYAssertTrue([condition waitWithTimeout:10 pollInterval:0.1],
conditionDescription);
}
+ (void)submitSyncPassphrase:(NSString*)passphrase {
[[EarlGrey selectElementWithMatcher:
grey_accessibilityID(
kSyncEncryptionPassphraseTextFieldAccessibilityIdentifier)]
performAction:grey_replaceText(passphrase)];
// grey_replaceText triggers textFieldDidEndEditing, which the
// SyncEncryptionPassphraseTableViewController will treat as a signInPressed,
// so there's no reason to tap the 'enter' button.
}
#pragma mark - Private
+ (void)signOutWithButton:(id<GREYMatcher>)buttonMatcher
confirmationLabelID:(int)confirmationLabelID {
[ChromeEarlGreyUI openSettingsMenu];
[ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
[ChromeEarlGreyUI tapAccountsMenuButton:buttonMatcher];
id<GREYMatcher> confirmationButtonMatcher = [ChromeMatchersAppInterface
buttonWithAccessibilityLabelID:confirmationLabelID];
[[EarlGrey selectElementWithMatcher:grey_allOf(confirmationButtonMatcher,
grey_not(buttonMatcher), nil)]
performAction:grey_tap()];
// Wait until the user is signed out. Use a longer timeout for cases where
// sign out also triggers a clear browsing data.
[ChromeEarlGrey
waitForUIElementToAppearWithMatcher:SettingsDoneButton()
timeout:base::test::ios::
kWaitForClearBrowsingDataTimeout];
[[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
performAction:grey_tap()];
[SigninEarlGrey verifySignedOut];
}
@end