| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import <memory> |
| |
| #import "base/strings/sys_string_conversions.h" |
| #import "base/test/ios/wait_util.h" |
| #import "base/threading/platform_thread.h" |
| #import "base/time/time.h" |
| #import "components/strings/grit/components_strings.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_matchers.h" |
| #import "ios/chrome/test/earl_grey/web_http_server_chrome_test_case.h" |
| #import "ios/chrome/test/scoped_eg_synchronization_disabler.h" |
| #import "ios/testing/earl_grey/earl_grey_test.h" |
| #import "ios/web/public/test/http_server/http_auth_response_provider.h" |
| #import "ios/web/public/test/http_server/http_server.h" |
| #import "ios/web/public/test/http_server/http_server_util.h" |
| #import "ui/base/l10n/l10n_util_mac.h" |
| #import "url/gurl.h" |
| |
| using base::test::ios::kWaitForPageLoadTimeout; |
| using base::test::ios::WaitUntilConditionOrTimeout; |
| |
| namespace { |
| |
| // Returns matcher for HTTP Authentication dialog. |
| id<GREYMatcher> HttpAuthDialog() { |
| NSString* title = l10n_util::GetNSStringWithFixup(IDS_LOGIN_DIALOG_TITLE); |
| return grey_allOf(chrome_test_util::StaticTextWithAccessibilityLabel(title), |
| grey_ancestor(grey_kindOfClass(UIButton.class)), nil); |
| } |
| |
| // Returns matcher for Username text field. |
| id<GREYMatcher> UsernameField() { |
| return grey_accessibilityValue(l10n_util::GetNSStringWithFixup( |
| IDS_IOS_HTTP_LOGIN_DIALOG_USERNAME_PLACEHOLDER)); |
| } |
| |
| // Returns matcher for Password text field. |
| id<GREYMatcher> PasswordField() { |
| return grey_accessibilityValue(l10n_util::GetNSStringWithFixup( |
| IDS_IOS_HTTP_LOGIN_DIALOG_PASSWORD_PLACEHOLDER)); |
| } |
| |
| // Returns matcher for Login button. |
| id<GREYMatcher> LoginButton() { |
| return chrome_test_util::ButtonWithAccessibilityLabelId( |
| IDS_LOGIN_DIALOG_OK_BUTTON_LABEL); |
| } |
| |
| // Waits until static text with IDS_LOGIN_DIALOG_TITLE label is displayed. |
| void WaitForHttpAuthDialog() { |
| BOOL dialog_shown = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ |
| NSError* error = nil; |
| [[EarlGrey selectElementWithMatcher:HttpAuthDialog()] |
| assertWithMatcher:grey_notNil() |
| error:&error]; |
| return !error; |
| }); |
| GREYAssert(dialog_shown, @"HTTP Authentication dialog was not shown"); |
| } |
| |
| } // namespace |
| |
| // Test case for HTTP Authentication flow. |
| @interface HTTPAuthTestCase : WebHttpServerChromeTestCase |
| @end |
| |
| @implementation HTTPAuthTestCase |
| |
| // Tests Basic HTTP Authentication with correct username and password. |
| - (void)testSuccessfullBasicAuth { |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // EG does not allow interactions with HTTP Dialog when loading spinner is |
| // animated. TODO(crbug.com/41294580): Enable this test on iPad when |
| // EarlGrey allows tapping dialog buttons with active page load spinner. |
| EARL_GREY_TEST_DISABLED(@"Tab Title not displayed on handset."); |
| } |
| |
| // EG synchronization disabled block. |
| { |
| // EG synchronizes with WKWebView. Disable synchronization for EG interation |
| // during when page is loading. |
| ScopedSynchronizationDisabler disabler; |
| GURL URL = web::test::HttpServer::MakeUrl("http://good-auth"); |
| web::test::SetUpHttpServer(std::make_unique<web::HttpAuthResponseProvider>( |
| URL, "GoodRealm", "gooduser", "goodpass")); |
| [ChromeEarlGrey loadURL:URL waitForCompletion:NO]; |
| WaitForHttpAuthDialog(); |
| |
| [[EarlGrey selectElementWithMatcher:UsernameField()] |
| performAction:grey_tap()]; |
| |
| // Wait for the keyboard to be shown. |
| base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.5)); |
| |
| // Enter valid username and password. |
| [[EarlGrey selectElementWithMatcher:UsernameField()] |
| performAction:grey_replaceText(@"gooduser")]; |
| [[EarlGrey selectElementWithMatcher:PasswordField()] |
| performAction:grey_replaceText(@"goodpass")]; |
| [[EarlGrey selectElementWithMatcher:LoginButton()] |
| performAction:grey_tap()]; |
| } // EG synchronization disabled block. |
| |
| const std::string pageText = web::HttpAuthResponseProvider::page_text(); |
| [ChromeEarlGrey waitForWebStateContainingText:pageText]; |
| } |
| |
| // Tests Basic HTTP Authentication with incorrect username and password. |
| - (void)testUnsuccessfullBasicAuth { |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // EG does not allow interactions with HTTP Dialog when loading spinner is |
| // animated. TODO(crbug.com/41294580): Enable this test on iPad when |
| // EarlGrey allows tapping dialog buttons with active page load spinner. |
| EARL_GREY_TEST_DISABLED(@"Tab Title not displayed on handset."); |
| } |
| |
| // EG synchronization disabled block. |
| { |
| // EG synchronizes with WKWebView. Disable synchronization for EG interation |
| // during when page is loading. |
| ScopedSynchronizationDisabler disabler; |
| GURL URL = web::test::HttpServer::MakeUrl("http://bad-auth"); |
| web::test::SetUpHttpServer(std::make_unique<web::HttpAuthResponseProvider>( |
| URL, "BadRealm", "baduser", "badpass")); |
| [ChromeEarlGrey loadURL:URL waitForCompletion:NO]; |
| WaitForHttpAuthDialog(); |
| |
| // Enter invalid username and password. |
| [[EarlGrey selectElementWithMatcher:UsernameField()] |
| performAction:grey_replaceText(@"gooduser")]; |
| [[EarlGrey selectElementWithMatcher:PasswordField()] |
| performAction:grey_replaceText(@"goodpass")]; |
| [[EarlGrey selectElementWithMatcher:LoginButton()] |
| performAction:grey_tap()]; |
| |
| // Ensure first dialog is dismissed before waiting for the second one. |
| base::PlatformThread::Sleep(base::Seconds(1)); |
| // Verifies that authentication was requested again. |
| WaitForHttpAuthDialog(); |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::CancelButton()] |
| performAction:grey_tap()]; |
| } // EG synchronization disabled block. |
| |
| [[EarlGrey selectElementWithMatcher:HttpAuthDialog()] |
| assertWithMatcher:grey_nil()]; |
| } |
| |
| // Tests Cancelling Basic HTTP Authentication. |
| - (void)testCancellingBasicAuth { |
| if ([ChromeEarlGrey isIPadIdiom]) { |
| // EG does not allow interactions with HTTP Dialog when loading spinner is |
| // animated. TODO(crbug.com/41294580): Enable this test on iPad when |
| // EarlGrey allows tapping dialog buttons with active page load spinner. |
| EARL_GREY_TEST_DISABLED(@"Tab Title not displayed on handset."); |
| } |
| |
| // EG synchronization disabled block. |
| { |
| // EG synchronizes with WKWebView. Disable synchronization for EG interation |
| // during when page is loading. |
| ScopedSynchronizationDisabler disabler; |
| GURL URL = web::test::HttpServer::MakeUrl("http://cancel-auth"); |
| web::test::SetUpHttpServer(std::make_unique<web::HttpAuthResponseProvider>( |
| URL, "CancellingRealm", "", "")); |
| [ChromeEarlGrey loadURL:URL waitForCompletion:NO]; |
| WaitForHttpAuthDialog(); |
| |
| id<GREYMatcher> cancelButtonMatcher = grey_allOf( |
| chrome_test_util::CancelButton(), |
| grey_not(grey_accessibilityTrait(UIAccessibilityTraitNotEnabled)), nil); |
| // Wait for element to become enabled because auth dialog buttons are |
| // initially disabled. See crbug.com/341353783 |
| [ChromeEarlGrey waitForUIElementToAppearWithMatcher:cancelButtonMatcher]; |
| |
| [[EarlGrey selectElementWithMatcher:cancelButtonMatcher] |
| performAction:grey_tap()]; |
| |
| } // EG synchronization disabled block. |
| |
| [[EarlGrey selectElementWithMatcher:HttpAuthDialog()] |
| assertWithMatcher:grey_nil()]; |
| } |
| |
| @end |