Index: ios/chrome/browser/web/forms_egtest.mm |
diff --git a/ios/chrome/browser/web/forms_egtest.mm b/ios/chrome/browser/web/forms_egtest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..00ce6b3531fc6ee59782068b2043873993949e0e |
--- /dev/null |
+++ b/ios/chrome/browser/web/forms_egtest.mm |
@@ -0,0 +1,289 @@ |
+// 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 "base/mac/scoped_nsobject.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "components/strings/grit/components_strings.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" |
+#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_earl_grey.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/http_server.h" |
+#import "ios/web/public/test/http_server_util.h" |
+#include "ios/web/public/test/response_providers/html_response_provider.h" |
+#include "ios/web/public/test/response_providers/html_response_provider_impl.h" |
+ |
+namespace { |
+ |
+// URL for a generic website in the user navigation flow. |
+const char kGenericUrl[] = "http://generic"; |
+ |
+// URL for the server to print the HTTP method and the request body. |
+const char kPrintFormDataUrl[] = "http://printFormData"; |
+ |
+// URL for the server that redirects to kPrintPostData with a 302. |
+const char kRedirectUrl[] = "http://redirect"; |
+ |
+// URL for the server to return a page that posts a form with some data to |
+// |kPrintPostData|. |
+const char kFormUrl[] = "http://formURL"; |
+ |
+// URL for the server to return a page that posts to |kRedirect|. |
+const char kRedirectFormUrl[] = "http://redirectFormURL"; |
+ |
+// Label for the button in the form. |
+const char kSubmitButton[] = "Submit"; |
+ |
+// Expected response from the server. |
+const char kExpectedPostData[] = "POST Data=Unicorn"; |
+ |
+} // namespace |
+ |
+// Tests submition of HTTP forms POST data including cases involving navigation. |
+@interface FormsTestCase : ChromeTestCase |
+@end |
+ |
+@implementation FormsTestCase |
+ |
+// Sets up server urls and responses. |
+- (void)setUp { |
+ [super setUp]; |
+ std::map<GURL, HtmlResponseProviderImpl::Response> responses; |
+ |
+ const char* formHtml = |
+ "<form method=\"post\" action=\"%s\">" |
+ "<textarea rows=\"1\" name=\"Data\">Unicorn</textarea>" |
+ "<input type=\"submit\" value=\"%s\" id=\"%s\">" |
+ "</form>"; |
+ GURL printFormDataUrl = web::test::HttpServer::MakeUrl(kPrintFormDataUrl); |
+ |
+ const GURL formUrl = web::test::HttpServer::MakeUrl(kFormUrl); |
+ responses[formUrl] = HtmlResponseProviderImpl::GetSimpleResponse( |
+ base::StringPrintf(formHtml, printFormDataUrl.spec().c_str(), |
+ kSubmitButton, kSubmitButton)); |
+ |
+ const GURL redirectFormUrl = web::test::HttpServer::MakeUrl(kRedirectFormUrl); |
+ const std::string redirectFormResponse = base::StringPrintf( |
+ formHtml, web::test::HttpServer::MakeUrl(kRedirectUrl).spec().c_str(), |
+ kSubmitButton, kSubmitButton); |
+ responses[redirectFormUrl] = |
+ HtmlResponseProviderImpl::GetSimpleResponse(redirectFormResponse); |
+ |
+ const GURL redirectUrl = web::test::HttpServer::MakeUrl(kRedirectUrl); |
+ responses[redirectUrl] = HtmlResponseProviderImpl::GetRedirectResponse( |
+ printFormDataUrl, net::HTTP_FOUND); |
+ |
+ std::unique_ptr<web::DataResponseProvider> provider( |
+ new HtmlResponseProvider(responses)); |
+ web::test::SetUpHttpServer(std::move(provider)); |
+} |
+ |
+// Submits the html form and verifies the destination url. |
+- (void)submitForm { |
+ chrome_test_util::TapWebViewElementWithId(kSubmitButton); |
+ |
+ GURL url = web::test::HttpServer::MakeUrl(kPrintFormDataUrl); |
+ id<GREYMatcher> URLMatcher = chrome_test_util::omniboxText(url.GetContent()); |
+ [[EarlGrey selectElementWithMatcher:URLMatcher] |
+ assertWithMatcher:grey_notNil()]; |
+} |
+ |
+// Waits for the |expectedResponse| within the web view. |
+- (void)waitForExpectedResponse:(std::string)expectedResponse { |
+ [[GREYCondition |
+ conditionWithName:@"Waiting for webview to display resulting text." |
+ block:^BOOL { |
+ id<GREYMatcher> webViewMatcher = |
+ chrome_test_util::webViewContainingText( |
+ expectedResponse); |
+ NSError* error = nil; |
+ [[EarlGrey selectElementWithMatcher:webViewMatcher] |
+ assertWithMatcher:grey_notNil() |
+ error:&error]; |
+ return error == nil; |
+ }] waitWithTimeout:5]; |
+} |
+ |
+// Waits for view with Tab History accessibility ID. |
+- (void)waitForTabHistoryView { |
+ [[GREYCondition conditionWithName:@"Waiting for Tab History to display." |
+ block:^BOOL { |
+ NSError* error = nil; |
+ id<GREYMatcher> tabHistory = |
+ grey_accessibilityID(@"Tab History"); |
+ [[EarlGrey selectElementWithMatcher:tabHistory] |
+ assertWithMatcher:grey_notNil() |
+ error:&error]; |
+ return error == nil; |
+ }] waitWithTimeout:5]; |
+} |
+ |
+// Reloads the web view and waits for the loading to complete. |
+// TODO(crbug.com/638674): Evaluate if this can move to shared code |
+- (void)reloadPage { |
+ base::scoped_nsobject<GenericChromeCommand> reloadCommand( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_RELOAD]); |
+ chrome_test_util::RunCommandWithActiveViewController(reloadCommand); |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+} |
+ |
+// Navigates back to the previous webpage. |
+- (void)goBack { |
+ base::scoped_nsobject<GenericChromeCommand> backCommand( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_BACK]); |
+ chrome_test_util::RunCommandWithActiveViewController(backCommand); |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+} |
+ |
+// Open back navigation history. |
+- (void)openBackHistory { |
+ id<GREYMatcher> back = |
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_ACCNAME_BACK); |
+ [[EarlGrey selectElementWithMatcher:back] performAction:grey_longPress()]; |
+} |
+ |
+// Navigates forward to a previous webpage. |
+// TODO(crbug.com/638674): Evaluate if this can move to shared code |
+- (void)goForward { |
+ base::scoped_nsobject<GenericChromeCommand> forwardCommand( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_FORWARD]); |
+ chrome_test_util::RunCommandWithActiveViewController(forwardCommand); |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+} |
+ |
+// Accepts the warning that the form POST data will be resent. |
+- (void)confirmResendWarning { |
+ id<GREYMatcher> resendWarning = |
+ chrome_test_util::buttonWithAccessibilityLabelId( |
+ IDS_HTTP_POST_WARNING_RESEND); |
+ [[EarlGrey selectElementWithMatcher:resendWarning] |
+ performAction:grey_longPress()]; |
+} |
+ |
+// Tests whether the request data is resent correctly. |
+- (void)testFormsResendPostData { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFormUrl)]; |
+ |
+ [self submitForm]; |
+ [self waitForExpectedResponse:kExpectedPostData]; |
+ |
+ [self reloadPage]; |
+ [self confirmResendWarning]; |
+ |
+ [self waitForExpectedResponse:kExpectedPostData]; |
+} |
+ |
+// Tests that a POST followed by navigating to a new page and then tapping back |
+// to the form result page resends data. |
+- (void)testFormsResendPostDataAfterTappingBack { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFormUrl)]; |
+ |
+ [self submitForm]; |
+ |
+ // Go to a new page. |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kGenericUrl)]; |
+ |
+ // Go back and check that the data is resent. |
+ [self goBack]; |
+ [self confirmResendWarning]; |
+ [self waitForExpectedResponse:kExpectedPostData]; |
+} |
+ |
+// Tests that a POST followed by tapping back to the form page and then tapping |
+// forward to the result page resends data. |
+- (void)testFormsResendPostDataAfterTappingBackAndForward { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFormUrl)]; |
+ [self submitForm]; |
+ |
+ [self goBack]; |
+ [self goForward]; |
+ [self confirmResendWarning]; |
+ [self waitForExpectedResponse:kExpectedPostData]; |
+} |
+ |
+// Tests that a POST followed by a new request and then index navigation to get |
+// back to the result page resends data. |
+- (void)testFormsResendPostDataAfterIndexNavigation { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFormUrl)]; |
+ [self submitForm]; |
+ |
+ // Go to a new page. |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kGenericUrl)]; |
+ |
+ [self openBackHistory]; |
+ [self waitForTabHistoryView]; |
+ |
+ const GURL printURL = web::test::HttpServer::MakeUrl(kPrintFormDataUrl); |
+ id<GREYMatcher> historyItem = |
+ grey_text(base::SysUTF8ToNSString(printURL.spec())); |
+ [[EarlGrey selectElementWithMatcher:historyItem] performAction:grey_tap()]; |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+ |
+ [self confirmResendWarning]; |
+ [self waitForExpectedResponse:kExpectedPostData]; |
+} |
+ |
+// When data is not re-sent, the request is done with a GET method. |
+- (void)testFormsDontResendPostData { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFormUrl)]; |
+ [self submitForm]; |
+ |
+ [self reloadPage]; |
+ |
+ // Abort the reload. |
+ if (IsIPadIdiom()) { |
+ // On tablet, dismiss the popover. |
+ base::scoped_nsobject<GREYElementMatcherBlock> matcher([ |
+ [GREYElementMatcherBlock alloc] |
+ initWithMatchesBlock:^BOOL(UIView* view) { |
+ return [NSStringFromClass([view class]) hasPrefix:@"UIDimmingView"]; |
+ } |
+ descriptionBlock:^(id<GREYDescription> description) { |
+ [description appendText:@"class prefixed with UIDimmingView"]; |
+ }]); |
+ [[EarlGrey selectElementWithMatcher:matcher] |
+ performAction:grey_tapAtPoint(CGPointMake(50.0f, 50.0f))]; |
+ } else { |
+ // On handset, dismiss via the cancel button. |
+ id<GREYMatcher> cancel = |
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_CANCEL); |
+ [[EarlGrey selectElementWithMatcher:cancel] performAction:grey_tap()]; |
+ } |
+ // Check that the POST is changed to a GET |
+ [self waitForExpectedResponse:"GET"]; |
+} |
+ |
+// Tests that a POST followed by a redirect does not show the popup. |
+- (void)testFormsDontResendPostDataAfterRedirect { |
+ [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kRedirectFormUrl)]; |
+ // Submit the form, which redirects before printing the data. |
+ [self submitForm]; |
+ // Check that the redirect changes the POST to a GET. |
+ [self waitForExpectedResponse:"GET"]; |
+ [self reloadPage]; |
+ |
+ // Check that the popup did not show |
+ id<GREYMatcher> resendWarning = |
+ chrome_test_util::buttonWithAccessibilityLabelId( |
+ IDS_HTTP_POST_WARNING_RESEND); |
+ [[EarlGrey selectElementWithMatcher:resendWarning] |
+ assertWithMatcher:grey_nil()]; |
+ |
+ [self waitForExpectedResponse:"GET"]; |
+} |
+ |
+@end |