| // 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. |
| |
| #import <UIKit/UIKit.h> |
| #import <XCTest/XCTest.h> |
| |
| #include <memory> |
| |
| #import "base/test/ios/wait_util.h" |
| #include "components/strings/grit/components_strings.h" |
| #import "ios/chrome/browser/passwords/password_manager_app_interface.h" |
| #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h" |
| #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h" |
| #import "ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #import "ios/chrome/test/earl_grey/chrome_actions.h" |
| #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" |
| #import "ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.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/web_http_server_chrome_test_case.h" |
| #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" |
| #import "ios/testing/earl_grey/earl_grey_test.h" |
| #include "net/test/embedded_test_server/default_handlers.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| constexpr char kFormUsername[] = "un"; |
| constexpr char kFormPassword[] = "pw"; |
| NSString* const kSavedCredentialLabel = @"Eguser, Hidden, Password"; |
| |
| namespace { |
| |
| using base::test::ios::kWaitForActionTimeout; |
| using base::test::ios::kWaitForUIElementTimeout; |
| using base::test::ios::WaitUntilConditionOrTimeout; |
| using base::test::ios::kWaitForActionTimeout; |
| using chrome_test_util::TapWebElementWithId; |
| using chrome_test_util::UseSuggestedPasswordMatcher; |
| |
| id<GREYMatcher> PasswordInfobar(int prompt_id) { |
| NSString* bannerLabel = |
| [NSString stringWithFormat:@"%@,%@", l10n_util::GetNSString(prompt_id), |
| kSavedCredentialLabel]; |
| return grey_allOf(grey_accessibilityID(kInfobarBannerViewIdentifier), |
| grey_accessibilityLabel(bannerLabel), nil); |
| } |
| |
| id<GREYMatcher> PasswordInfobarButton(int button_id) { |
| return chrome_test_util::ButtonWithAccessibilityLabelId(button_id); |
| } |
| |
| id<GREYMatcher> SuggestPasswordChip() { |
| return grey_allOf( |
| grey_accessibilityLabel(l10n_util::GetNSString(IDS_IOS_SUGGEST_PASSWORD)), |
| nil); |
| } |
| |
| BOOL WaitForKeyboardToAppear() { |
| GREYCondition* waitForKeyboard = [GREYCondition |
| conditionWithName:@"Wait for keyboard" |
| block:^BOOL { |
| return [EarlGrey isKeyboardShownWithError:nil]; |
| }]; |
| return [waitForKeyboard waitWithTimeout:kWaitForActionTimeout]; |
| } |
| |
| } // namespace |
| |
| @interface PasswordControllerEGTest : WebHttpServerChromeTestCase |
| @end |
| |
| @implementation PasswordControllerEGTest |
| |
| - (void)setUp { |
| [super setUp]; |
| |
| // Set up server. |
| net::test_server::RegisterDefaultHandlers(self.testServer); |
| GREYAssertTrue(self.testServer->Start(), @"Server did not start."); |
| } |
| |
| - (void)tearDown { |
| [PasswordManagerAppInterface clearCredentials]; |
| [super tearDown]; |
| } |
| |
| #pragma mark - Helper methods |
| |
| // Loads simple page on localhost. |
| - (void)loadLoginPage { |
| // Loads simple page. It is on localhost so it is considered a secure context. |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/simple_login_form.html")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Login form."]; |
| } |
| |
| #pragma mark - Tests |
| |
| // Tests that save password prompt is shown on new login. |
| // TODO(crbug.com/1192446): Reenable this test. |
| - (void)DISABLED_testSavePromptAppearsOnFormSubmission { |
| [self loadLoginPage]; |
| |
| // Simulate user interacting with fields. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId(kFormUsername)]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; |
| |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId("submit_button")]; |
| |
| // Wait until the save password prompt becomes visible. |
| [ChromeEarlGrey |
| waitForUIElementToAppearWithMatcher: |
| PasswordInfobar(IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT)]; |
| |
| [[EarlGrey selectElementWithMatcher:PasswordInfobarButton( |
| IDS_IOS_PASSWORD_MANAGER_SAVE_BUTTON)] |
| performAction:grey_tap()]; |
| |
| // Wait until the save password infobar disappears. |
| [ChromeEarlGrey |
| waitForUIElementToDisappearWithMatcher: |
| PasswordInfobar(IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT)]; |
| |
| int credentialsCount = [PasswordManagerAppInterface storedCredentialsCount]; |
| GREYAssertEqual(1, credentialsCount, @"Wrong number of stored credentials."); |
| } |
| |
| // Tests that update password prompt is shown on submitting the new password |
| // for an already stored login. |
| // TODO(crbug.com/1330896): Test fails on simulator. |
| #if TARGET_IPHONE_SIMULATOR |
| #define MAYBE_testUpdatePromptAppearsOnFormSubmission \ |
| DISABLED_testUpdatePromptAppearsOnFormSubmission |
| #else |
| #define MAYBE_testUpdatePromptAppearsOnFormSubmission \ |
| testUpdatePromptAppearsOnFormSubmission |
| #endif |
| - (void)MAYBE_testUpdatePromptAppearsOnFormSubmission { |
| // Load the page the first time an store credentials. |
| [self loadLoginPage]; |
| [PasswordManagerAppInterface storeCredentialWithUsername:@"Eguser" |
| password:@"OldPass"]; |
| int credentialsCount = [PasswordManagerAppInterface storedCredentialsCount]; |
| GREYAssertEqual(1, credentialsCount, @"Wrong number of initial credentials."); |
| |
| // Load the page again and have a new password value to save. |
| [self loadLoginPage]; |
| // Simulate user interacting with fields. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId(kFormUsername)]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; |
| |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:chrome_test_util::TapWebElementWithId("submit_button")]; |
| |
| // Wait until the update password prompt becomes visible. |
| [ChromeEarlGrey |
| waitForUIElementToAppearWithMatcher: |
| PasswordInfobar(IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD)]; |
| |
| [[EarlGrey |
| selectElementWithMatcher:PasswordInfobarButton( |
| IDS_IOS_PASSWORD_MANAGER_UPDATE_BUTTON)] |
| performAction:grey_tap()]; |
| |
| // Wait until the update password infobar disappears. |
| [ChromeEarlGrey |
| waitForUIElementToDisappearWithMatcher: |
| PasswordInfobar(IDS_IOS_PASSWORD_MANAGER_UPDATE_PASSWORD)]; |
| |
| credentialsCount = [PasswordManagerAppInterface storedCredentialsCount]; |
| GREYAssertEqual(1, credentialsCount, @"Wrong number of final credentials."); |
| } |
| |
| // Tests password generation flow. |
| // TODO(crbug.com/1221635) This fails on iPhone 14.5+ |
| - (void)DISABLED_testPasswordGeneration { |
| #if TARGET_IPHONE_SIMULATOR |
| // TODO(crbug.com/1194134): Reenable this test. |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| EARL_GREY_TEST_SKIPPED(@"Skipped for iPad (test is flaky)"); |
| } |
| #endif |
| [SigninEarlGreyUI signinWithFakeIdentity:[FakeChromeIdentity fakeIdentity1]]; |
| [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:10.0]; |
| |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/simple_signup_form.html")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Signup form."]; |
| |
| // Verify that the target field is empty. |
| NSString* emptyFieldCondition = |
| [NSString stringWithFormat:@"document.getElementById('%s').value === ''", |
| kFormPassword]; |
| [ChromeEarlGrey waitForJavaScriptCondition:emptyFieldCondition]; |
| |
| // Bring up the keyboard. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] |
| performAction:TapWebElementWithId(kFormPassword)]; |
| |
| // Wait for the accessory icon to appear. |
| WaitForKeyboardToAppear(); |
| |
| // Tap on a 'Suggest Password...' chip. |
| [[EarlGrey selectElementWithMatcher:SuggestPasswordChip()] |
| performAction:grey_tap()]; |
| |
| // Confirm by tapping on the 'Use Suggested Password' button. |
| [[EarlGrey selectElementWithMatcher:UseSuggestedPasswordMatcher()] |
| performAction:grey_tap()]; |
| |
| // Verify that the target field is not empty. |
| NSString* filledFieldCondition = |
| [NSString stringWithFormat:@"document.getElementById('%s').value !== ''", |
| kFormPassword]; |
| [ChromeEarlGrey waitForJavaScriptCondition:filledFieldCondition]; |
| } |
| |
| @end |