| // Copyright 2016 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 <XCTest/XCTest.h> |
| #include <map> |
| #include <memory> |
| #include <string> |
| |
| #include "base/ios/ios_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/content_settings/core/common/content_settings.h" |
| #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" |
| #import "ios/chrome/browser/ui/commands/generic_chrome_command.h" |
| #include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
| #include "ios/chrome/browser/ui/ui_util.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #import "ios/chrome/test/app/chrome_test_util.h" |
| #include "ios/chrome/test/app/navigation_test_util.h" |
| #include "ios/chrome/test/app/web_view_interaction_test_util.h" |
| #import "ios/chrome/test/earl_grey/chrome_assertions.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_test_case.h" |
| #import "ios/testing/wait_util.h" |
| #import "ios/web/public/test/earl_grey/web_view_actions.h" |
| #import "ios/web/public/test/earl_grey/web_view_matchers.h" |
| #import "ios/web/public/test/http_server.h" |
| #include "ios/web/public/test/http_server_util.h" |
| #include "ios/web/public/test/response_providers/data_response_provider.h" |
| #include "net/http/http_response_headers.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| using chrome_test_util::OmniboxText; |
| using chrome_test_util::WebViewContainingText; |
| |
| namespace { |
| |
| // URL used for the reload test. |
| const char kReloadTestUrl[] = "http://mock/reloadTest"; |
| |
| // Returns the number of serviced requests in HTTP body. |
| class ReloadResponseProvider : public web::DataResponseProvider { |
| public: |
| ReloadResponseProvider() : request_number_(0) {} |
| |
| // URL used for the reload test. |
| static GURL GetReloadTestUrl() { |
| return web::test::HttpServer::MakeUrl(kReloadTestUrl); |
| } |
| |
| bool CanHandleRequest(const Request& request) override { |
| return request.url == ReloadResponseProvider::GetReloadTestUrl(); |
| } |
| |
| void GetResponseHeadersAndBody( |
| const Request& request, |
| scoped_refptr<net::HttpResponseHeaders>* headers, |
| std::string* response_body) override { |
| DCHECK_EQ(ReloadResponseProvider::GetReloadTestUrl(), request.url); |
| *headers = GetDefaultResponseHeaders(); |
| *response_body = GetResponseBody(request_number_++); |
| } |
| |
| // static |
| static std::string GetResponseBody(int request_number) { |
| return base::StringPrintf("Load request %d", request_number); |
| } |
| |
| private: |
| int request_number_; // Count of requests received by the response provider. |
| }; |
| |
| // ScopedBlockPopupsPref modifies the block popups preference and resets the |
| // preference to its original value when this object goes out of scope. |
| // TODO(crbug.com/638674): Evaluate if this can move to shared code |
| class ScopedBlockPopupsPref { |
| public: |
| ScopedBlockPopupsPref(ContentSetting setting) { |
| original_setting_ = GetPrefValue(); |
| SetPrefValue(setting); |
| } |
| ~ScopedBlockPopupsPref() { SetPrefValue(original_setting_); } |
| |
| private: |
| // Gets the current value of the preference. |
| ContentSetting GetPrefValue() { |
| ContentSetting popupSetting = |
| ios::HostContentSettingsMapFactory::GetForBrowserState( |
| chrome_test_util::GetOriginalBrowserState()) |
| ->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS, NULL); |
| return popupSetting; |
| } |
| |
| // Sets the preference to the given value. |
| void SetPrefValue(ContentSetting setting) { |
| DCHECK(setting == CONTENT_SETTING_BLOCK || |
| setting == CONTENT_SETTING_ALLOW); |
| ios::ChromeBrowserState* state = |
| chrome_test_util::GetOriginalBrowserState(); |
| ios::HostContentSettingsMapFactory::GetForBrowserState(state) |
| ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS, setting); |
| } |
| |
| // Saves the original pref setting so that it can be restored when the scoper |
| // is destroyed. |
| ContentSetting original_setting_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedBlockPopupsPref); |
| }; |
| } // namespace |
| |
| // Tests web browsing scenarios. |
| @interface BrowsingTestCase : ChromeTestCase |
| @end |
| |
| @implementation BrowsingTestCase |
| |
| // Matcher for the title of the current tab (on tablet only). |
| id<GREYMatcher> TabWithTitle(const std::string& tab_title) { |
| id<GREYMatcher> notPartOfOmnibox = |
| grey_not(grey_ancestor(chrome_test_util::Omnibox())); |
| return grey_allOf(grey_accessibilityLabel(base::SysUTF8ToNSString(tab_title)), |
| notPartOfOmnibox, nil); |
| } |
| |
| // Matcher for a Go button that is interactable. |
| id<GREYMatcher> GoButtonMatcher() { |
| return grey_allOf(grey_accessibilityID(@"Go"), grey_interactable(), nil); |
| } |
| |
| // Tests that page successfully reloads. |
| - (void)testReload { |
| // Set up test HTTP server responses. |
| std::unique_ptr<web::DataResponseProvider> provider( |
| new ReloadResponseProvider()); |
| web::test::SetUpHttpServer(std::move(provider)); |
| |
| GURL URL = ReloadResponseProvider::GetReloadTestUrl(); |
| [ChromeEarlGrey loadURL:URL]; |
| std::string expectedBodyBeforeReload( |
| ReloadResponseProvider::GetResponseBody(0 /* request number */)); |
| [[EarlGrey |
| selectElementWithMatcher:WebViewContainingText(expectedBodyBeforeReload)] |
| assertWithMatcher:grey_notNil()]; |
| |
| [ChromeEarlGreyUI reload]; |
| std::string expectedBodyAfterReload( |
| ReloadResponseProvider::GetResponseBody(1 /* request_number */)); |
| [[EarlGrey |
| selectElementWithMatcher:WebViewContainingText(expectedBodyAfterReload)] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests that a tab's title is based on the URL when no other information is |
| // available. |
| - (void)testBrowsingTabTitleSetFromURL { |
| if (!IsIPadIdiom()) { |
| EARL_GREY_TEST_SKIPPED(@"Tab Title not displayed on handset."); |
| } |
| |
| web::test::SetUpFileBasedHttpServer(); |
| |
| const GURL destinationURL = web::test::HttpServer::MakeUrl( |
| "http://ios/testing/data/http_server_files/destination.html"); |
| [ChromeEarlGrey loadURL:destinationURL]; |
| |
| // Add 3 for the "://" which is not considered part of the scheme |
| std::string URLWithoutScheme = |
| destinationURL.spec().substr(destinationURL.scheme().length() + 3); |
| |
| [[EarlGrey selectElementWithMatcher:TabWithTitle(URLWithoutScheme)] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| // Tests that after a PDF is loaded, the title appears in the tab bar on iPad. |
| - (void)testPDFLoadTitle { |
| if (!IsIPadIdiom()) { |
| EARL_GREY_TEST_SKIPPED(@"Tab Title not displayed on handset."); |
| } |
| |
| web::test::SetUpFileBasedHttpServer(); |
| |
| const GURL destinationURL = web::test::HttpServer::MakeUrl( |
| "http://ios/testing/data/http_server_files/testpage.pdf"); |
| [ChromeEarlGrey loadURL:destinationURL]; |
| |
| // Add 3 for the "://" which is not considered part of the scheme |
| std::string URLWithoutScheme = |
| destinationURL.spec().substr(destinationURL.scheme().length() + 3); |
| |
| [[EarlGrey selectElementWithMatcher:TabWithTitle(URLWithoutScheme)] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| // Tests that tab title is set to the specified title from a JavaScript. |
| - (void)testBrowsingTabTitleSetFromScript { |
| if (!IsIPadIdiom()) { |
| EARL_GREY_TEST_SKIPPED(@"Tab Title not displayed on handset."); |
| } |
| |
| const char* kPageTitle = "Some title"; |
| const GURL URL = GURL(base::StringPrintf( |
| "data:text/html;charset=utf-8,<script>document.title = " |
| "\"%s\"</script>", |
| kPageTitle)); |
| [ChromeEarlGrey loadURL:URL]; |
| |
| [[EarlGrey selectElementWithMatcher:TabWithTitle(kPageTitle)] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| // Tests clicking a link with target="_blank" and "event.stopPropagation()" |
| // opens a new tab. |
| - (void)testBrowsingStopPropagation { |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL = web::test::HttpServer::MakeUrl("http://stopPropagation"); |
| const GURL destinationURL = |
| web::test::HttpServer::MakeUrl("http://destination"); |
| // This is a page with a link to |kDestination|. |
| responses[URL] = base::StringPrintf( |
| "<a id='link' href='%s' target='_blank' " |
| "onclick='event.stopPropagation()'>link</a>", |
| destinationURL.spec().c_str()); |
| // This is the destination page; it just contains some text. |
| responses[destinationURL] = "You've arrived!"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| ScopedBlockPopupsPref prefSetter(CONTENT_SETTING_ALLOW); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| chrome_test_util::AssertMainTabCount(1); |
| |
| chrome_test_util::TapWebViewElementWithId("link"); |
| |
| chrome_test_util::AssertMainTabCount(2); |
| |
| // Verify the new tab was opened with the expected URL. |
| [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests clicking a relative link with target="_blank" and |
| // "event.stopPropagation()" opens a new tab. |
| - (void)testBrowsingStopPropagationRelativePath { |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL = web::test::HttpServer::MakeUrl("http://stopPropRel"); |
| const GURL destinationURL = |
| web::test::HttpServer::MakeUrl("http://stopPropRel/#test"); |
| // This is page with a relative link to "#test". |
| responses[URL] = |
| "<a id='link' href='#test' target='_blank' " |
| "onclick='event.stopPropagation()'>link</a>"; |
| // This is the page that should be showing at the end of the test. |
| responses[destinationURL] = "You've arrived!"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| ScopedBlockPopupsPref prefSetter(CONTENT_SETTING_ALLOW); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| chrome_test_util::AssertMainTabCount(1); |
| |
| chrome_test_util::TapWebViewElementWithId("link"); |
| |
| chrome_test_util::AssertMainTabCount(2); |
| |
| // Verify the new tab was opened with the expected URL. |
| [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests that clicking a link with URL changed by onclick uses the href of the |
| // anchor tag instead of the one specified in JavaScript. Also verifies a new |
| // tab is opened by target '_blank'. |
| // TODO(crbug.com/688223): WKWebView does not open a new window as expected by |
| // this test. |
| - (void)DISABLED_testBrowsingPreventDefaultWithLinkOpenedByJavascript { |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL = web::test::HttpServer::MakeUrl( |
| "http://preventDefaultWithLinkOpenedByJavascript"); |
| const GURL anchorURL = |
| web::test::HttpServer::MakeUrl("http://anchorDestination"); |
| const GURL destinationURL = |
| web::test::HttpServer::MakeUrl("http://javaScriptDestination"); |
| // This is a page with a link where the href and JavaScript are setting the |
| // destination to two different URLs so the test can verify which one the |
| // browser uses. |
| responses[URL] = base::StringPrintf( |
| "<a id='link' href='%s' target='_blank' " |
| "onclick='window.location.href=\"%s\"; " |
| "event.stopPropagation()' id='link'>link</a>", |
| anchorURL.spec().c_str(), destinationURL.spec().c_str()); |
| responses[anchorURL] = "anchor destination"; |
| |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| ScopedBlockPopupsPref prefSetter(CONTENT_SETTING_ALLOW); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| chrome_test_util::AssertMainTabCount(1); |
| |
| chrome_test_util::TapWebViewElementWithId("link"); |
| |
| chrome_test_util::AssertMainTabCount(2); |
| |
| // Verify the new tab was opened with the expected URL. |
| [[EarlGrey selectElementWithMatcher:OmniboxText(anchorURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests tapping a link that navigates to a page that immediately navigates |
| // again via document.location.href. |
| - (void)testBrowsingWindowDataLinkScriptRedirect { |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL = |
| web::test::HttpServer::MakeUrl("http://windowDataLinkScriptRedirect"); |
| const GURL intermediateURL = |
| web::test::HttpServer::MakeUrl("http://intermediate"); |
| const GURL destinationURL = |
| web::test::HttpServer::MakeUrl("http://destination"); |
| // This is a page with a link to the intermediate page. |
| responses[URL] = |
| base::StringPrintf("<a id='link' href='%s' target='_blank'>link</a>", |
| intermediateURL.spec().c_str()); |
| // This intermediate page uses JavaScript to immediately navigate to the |
| // destination page. |
| responses[intermediateURL] = |
| base::StringPrintf("<script>document.location.href=\"%s\"</script>", |
| destinationURL.spec().c_str()); |
| // This is the page that should be showing at the end of the test. |
| responses[destinationURL] = "You've arrived!"; |
| |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| ScopedBlockPopupsPref prefSetter(CONTENT_SETTING_ALLOW); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| chrome_test_util::AssertMainTabCount(1); |
| |
| chrome_test_util::TapWebViewElementWithId("link"); |
| |
| chrome_test_util::AssertMainTabCount(2); |
| |
| // Verify the new tab was opened with the expected URL. |
| [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests that a link with a JavaScript-based navigation changes the page and |
| // that the back button works as expected afterwards. |
| - (void)testBrowsingJavaScriptBasedNavigation { |
| std::map<GURL, std::string> responses; |
| const GURL URL = web::test::HttpServer::MakeUrl("http://origin"); |
| const GURL destURL = web::test::HttpServer::MakeUrl("http://destination"); |
| // Page containing a link with onclick attribute that sets window.location |
| // to the destination URL. |
| responses[URL] = base::StringPrintf( |
| "<a href='#' onclick=\"window.location='%s';\" id='link'>Link</a>", |
| destURL.spec().c_str()); |
| // Page with some text. |
| responses[destURL] = "You've arrived!"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| chrome_test_util::TapWebViewElementWithId("link"); |
| |
| [[EarlGrey selectElementWithMatcher:OmniboxText(destURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(URL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // TODO(crbug.com/638674): Evaluate if this can move to shared code |
| // Navigates back to the previous webpage. |
| - (void)goBack { |
| GenericChromeCommand* backCommand = |
| [[GenericChromeCommand alloc] initWithTag:IDC_BACK]; |
| chrome_test_util::RunCommandWithActiveViewController(backCommand); |
| |
| [ChromeEarlGrey waitForPageToFinishLoading]; |
| } |
| |
| // Navigates forward to a previous webpage. |
| // TODO(crbug.com/638674): Evaluate if this can move to shared code |
| - (void)goForward { |
| GenericChromeCommand* forwardCommand = |
| [[GenericChromeCommand alloc] initWithTag:IDC_FORWARD]; |
| chrome_test_util::RunCommandWithActiveViewController(forwardCommand); |
| |
| [ChromeEarlGrey waitForPageToFinishLoading]; |
| } |
| |
| // Tests that a link with WebUI URL does not trigger a load. WebUI pages may |
| // have increased power and using the same web process (which may potentially |
| // be controlled by an attacker) is dangerous. |
| - (void)testTapLinkWithWebUIURL { |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL(web::test::HttpServer::MakeUrl("http://pageWithWebUILink")); |
| const char kPageHTML[] = |
| "<script>" |
| " function printMsg() {" |
| " document.body.appendChild(document.createTextNode('Hello world!'));" |
| " }" |
| "</script>" |
| "<a href='chrome://version' id='link' onclick='printMsg()'>Version</a>"; |
| responses[URL] = kPageHTML; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| // Assert that test is starting with one tab. |
| chrome_test_util::AssertMainTabCount(1U); |
| chrome_test_util::AssertIncognitoTabCount(0U); |
| |
| [ChromeEarlGrey loadURL:URL]; |
| |
| // Tap on chrome://version link. |
| [ChromeEarlGrey tapWebViewElementWithID:@"link"]; |
| |
| // Verify that page did not change by checking its URL and message printed by |
| // onclick event. |
| [[EarlGrey selectElementWithMatcher:OmniboxText("chrome://version")] |
| assertWithMatcher:grey_nil()]; |
| [[EarlGrey selectElementWithMatcher:WebViewContainingText("Hello world!")] |
| assertWithMatcher:grey_notNil()]; |
| |
| // Verify that no new tabs were open which could load chrome://version. |
| chrome_test_util::AssertMainTabCount(1U); |
| } |
| |
| // Tests that pressing the button on a POST-based form with same-page action |
| // does not change the page and that the back button works as expected |
| // afterwards. |
| - (void)testBrowsingPostToSamePage { |
| // TODO(crbug.com/714303): Re-enable this test on devices. |
| #if !TARGET_IPHONE_SIMULATOR |
| EARL_GREY_TEST_DISABLED(@"Test disabled on device."); |
| #endif |
| |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL firstURL = web::test::HttpServer::MakeUrl("http://first"); |
| const GURL formURL = web::test::HttpServer::MakeUrl("http://form"); |
| // This is just a page with some text. |
| responses[firstURL] = "foo"; |
| // This is a page with at button that posts to the current URL. |
| responses[formURL] = |
| "<form method='post'>" |
| "<input value='button' type='submit' id='button'></form>"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| // Open the first URL so it's in history. |
| [ChromeEarlGrey loadURL:firstURL]; |
| |
| // Open the second URL, tap the button, and verify the browser navigates to |
| // the expected URL. |
| [ChromeEarlGrey loadURL:formURL]; |
| chrome_test_util::TapWebViewElementWithId("button"); |
| [[EarlGrey selectElementWithMatcher:OmniboxText(formURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| |
| // Go back once and verify the browser navigates to the form URL. |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(formURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| |
| // Go back a second time and verify the browser navigates to the first URL. |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(firstURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests that evaluating user JavaScript that causes navigation correctly |
| // modifies history. |
| - (void)testBrowsingUserJavaScriptNavigation { |
| // TODO(crbug.com/640220): Keyboard entry inside the omnibox fails only on |
| // iPad running iOS 10. |
| if (IsIPadIdiom() && base::ios::IsRunningOnIOS10OrLater()) |
| return; |
| |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL startURL = web::test::HttpServer::MakeUrl("http://startpage"); |
| responses[startURL] = "<html><body><p>Ready to begin.</p></body></html>"; |
| const GURL targetURL = web::test::HttpServer::MakeUrl("http://targetpage"); |
| responses[targetURL] = "<html><body><p>You've arrived!</p></body></html>"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| // Load the first page and run JS (using the codepath that user-entered JS in |
| // the omnibox would take, not page-triggered) that should navigate. |
| [ChromeEarlGrey loadURL:startURL]; |
| |
| NSString* script = |
| [NSString stringWithFormat:@"javascript:window.location='%s'", |
| targetURL.spec().c_str()]; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] |
| performAction:grey_typeText(script)]; |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Go")] |
| performAction:grey_tap()]; |
| [ChromeEarlGrey waitForPageToFinishLoading]; |
| |
| [[EarlGrey selectElementWithMatcher:OmniboxText(targetURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(startURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tests that evaluating non-navigation user JavaScript doesn't affect history. |
| - (void)testBrowsingUserJavaScriptWithoutNavigation { |
| // TODO(crbug.com/640220): Keyboard entry inside the omnibox fails only on |
| // iPad running iOS 10. |
| if (IsIPadIdiom() && base::ios::IsRunningOnIOS10OrLater()) |
| return; |
| |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL firstURL = web::test::HttpServer::MakeUrl("http://firstURL"); |
| const std::string firstResponse = "Test Page 1"; |
| const GURL secondURL = web::test::HttpServer::MakeUrl("http://secondURL"); |
| const std::string secondResponse = "Test Page 2"; |
| responses[firstURL] = firstResponse; |
| responses[secondURL] = secondResponse; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| [ChromeEarlGrey loadURL:firstURL]; |
| [ChromeEarlGrey loadURL:secondURL]; |
| |
| // Execute some JavaScript in the omnibox. |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] |
| performAction:grey_typeText(@"javascript:document.write('foo')")]; |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Go")] |
| performAction:grey_tap()]; |
| |
| id<GREYMatcher> webView = chrome_test_util::WebViewContainingText("foo"); |
| [[EarlGrey selectElementWithMatcher:webView] assertWithMatcher:grey_notNil()]; |
| |
| // Verify that the JavaScript did not affect history by going back and then |
| // forward again. |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(firstURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| [self goForward]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(secondURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| // Tap the text field indicated by |ID| to open the keyboard, and then |
| // press the keyboard's "Go" button to submit the form. |
| - (void)submitFormUsingKeyboardGoButtonWithInputID:(const std::string&)ID { |
| // Disable EarlGrey's synchronization since it is blocked by opening the |
| // keyboard from a web view. |
| [[GREYConfiguration sharedInstance] |
| setValue:@NO |
| forConfigKey:kGREYConfigKeySynchronizationEnabled]; |
| |
| // Wait for web view to be interactable before tapping. |
| GREYCondition* interactableCondition = [GREYCondition |
| conditionWithName:@"Wait for web view to be interactable." |
| block:^BOOL { |
| NSError* error = nil; |
| id<GREYMatcher> webViewMatcher = WebViewInWebState( |
| chrome_test_util::GetCurrentWebState()); |
| [[EarlGrey selectElementWithMatcher:webViewMatcher] |
| assertWithMatcher:grey_interactable() |
| error:&error]; |
| return !error; |
| }]; |
| GREYAssert( |
| [interactableCondition waitWithTimeout:testing::kWaitForUIElementTimeout], |
| @"Web view did not become interactable."); |
| |
| web::WebState* currentWebState = chrome_test_util::GetCurrentWebState(); |
| [[EarlGrey selectElementWithMatcher:web::WebViewInWebState(currentWebState)] |
| performAction:web::WebViewTapElement(currentWebState, ID)]; |
| |
| // Wait until the keyboard shows up before tapping. |
| GREYCondition* condition = [GREYCondition |
| conditionWithName:@"Wait for the keyboard to show up." |
| block:^BOOL { |
| NSError* error = nil; |
| [[EarlGrey selectElementWithMatcher:GoButtonMatcher()] |
| assertWithMatcher:grey_notNil() |
| error:&error]; |
| return (error == nil); |
| }]; |
| GREYAssert([condition waitWithTimeout:10], |
| @"No keyboard with 'Go' button showed up."); |
| |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Go")] |
| performAction:grey_tap()]; |
| |
| // Reenable synchronization now that the keyboard has been closed. |
| [[GREYConfiguration sharedInstance] |
| setValue:@YES |
| forConfigKey:kGREYConfigKeySynchronizationEnabled]; |
| } |
| |
| // Tests that submitting a POST-based form by tapping the 'Go' button on the |
| // keyboard navigates to the correct URL and the back button works as expected |
| // afterwards. |
| // TODO(crbug.com/711108): Move test to forms_egtest.mm. |
| - (void)testBrowsingPostEntryWithKeyboard { |
| // TODO(crbug.com/704618): Re-enable this test on devices. |
| #if !TARGET_IPHONE_SIMULATOR |
| EARL_GREY_TEST_DISABLED(@"Test disabled on device."); |
| #endif |
| |
| // Create map of canned responses and set up the test HTML server. |
| std::map<GURL, std::string> responses; |
| const GURL URL = |
| web::test::HttpServer::MakeUrl("http://postEntryWithKeyboard"); |
| const GURL destinationURL = web::test::HttpServer::MakeUrl("http://foo"); |
| // This is a page this an input text field and a button that posts to the |
| // destination. |
| responses[URL] = base::StringPrintf( |
| "hello!" |
| "<form action='%s' method='post'>" |
| "<input value='textfield' id='textfield' type='text'></label>" |
| "<input type='submit'></form>", |
| destinationURL.spec().c_str()); |
| // This is the page that should be showing at the end of the test. |
| responses[destinationURL] = "baz!"; |
| web::test::SetUpSimpleHttpServer(responses); |
| |
| // Open the URL, focus the textfield,and submit via keyboard. |
| [ChromeEarlGrey loadURL:URL]; |
| [[EarlGrey selectElementWithMatcher:WebViewContainingText("hello!")] |
| assertWithMatcher:grey_notNil()]; |
| |
| [self submitFormUsingKeyboardGoButtonWithInputID:"textfield"]; |
| |
| // Verify that the browser navigates to the expected URL. |
| [[EarlGrey selectElementWithMatcher:WebViewContainingText("baz!")] |
| assertWithMatcher:grey_notNil()]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| |
| // Go back and verify that the browser navigates to the original URL. |
| [self goBack]; |
| [[EarlGrey selectElementWithMatcher:WebViewContainingText("hello!")] |
| assertWithMatcher:grey_notNil()]; |
| [[EarlGrey selectElementWithMatcher:OmniboxText(URL.GetContent())] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| @end |