Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(570)

Unified Diff: ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm

Issue 2588713002: Upstream Chrome on iOS source code [4/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
diff --git a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..2dce5e7f42b33741ebaa9abeb9f09be9320008a2
--- /dev/null
+++ b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
@@ -0,0 +1,511 @@
+// 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 <EarlGrey/EarlGrey.h>
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+#import "base/strings/sys_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/dialogs/dialog_presenter.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/chrome/test/app/chrome_test_util.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/earl_grey/disabled_test_macros.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/web_state/web_state.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#import "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// Enum specifying different types of JavaScript alerts:
+// - JavaScriptAlertType::ALERT - Dialog with only one OK button.
+// - JavaScriptAlertType::CONFIRMATION - Dialog with OK and Cancel button.
+// - JavaScriptAlertType::PROMPT - Dialog with OK button, cancel button, and
+// a text field.
+enum class JavaScriptAlertType : NSUInteger { ALERT, CONFIRMATION, PROMPT };
+
+// Script to inject that will show an alert. The document's body will be reset
+// to |kAlertResultBody| after the dialog is dismissed.
+const char kAlertMessage[] = "This is a JavaScript alert.";
+const char kAlertResultBody[] = "JAVASCRIPT ALERT WAS DISMISSED";
+const char kJavaScriptAlertTestScriptFormat[] =
+ "(function(){ "
+ " alert(\"%@\");"
+ " document.body.innerHTML = \"%@\";"
+ "})();";
+NSString* GetJavaScriptAlertTestScript() {
+ return [NSString stringWithFormat:@(kJavaScriptAlertTestScriptFormat),
+ @(kAlertMessage), @(kAlertResultBody)];
+}
+
+// Script to inject that will show a confirmation dialog. The document's body
+// will be reset to |kConfirmationResultBodyOK| or
+// |kConfirmationResultBodyCancelled| depending on whether the OK or Cancel
+// button was tapped.
+const char kConfirmationMessage[] = "This is a JavaScript confirmation.";
+const char kConfirmationResultBodyOK[] = "Okay";
+const char kConfirmationResultBodyCancelled[] = "Cancelled";
+const char kJavaScriptConfirmationScriptFormat[] =
+ "(function(){ "
+ " if (confirm(\"%@\") == true) {"
+ " document.body.innerHTML = \"%@\";"
+ " } else {"
+ " document.body.innerHTML = \"%@\";"
+ " }"
+ "})();";
+NSString* GetJavaScriptConfirmationTestScript() {
+ return [NSString stringWithFormat:@(kJavaScriptConfirmationScriptFormat),
+ @(kConfirmationMessage),
+ @(kConfirmationResultBodyOK),
+ @(kConfirmationResultBodyCancelled)];
+}
+
+// Script to inject that will show a prompt dialog. The document's body will be
+// reset to |kPromptResultBodyCancelled| or |kPromptTestUserInput| depending on
+// whether the OK or Cancel button was tapped.
+const char kPromptMessage[] = "This is a JavaScript prompt.";
+const char kPromptResultBodyCancelled[] = "Cancelled";
+const char kPromptTestUserInput[] = "test";
+const char kJavaScriptPromptTestScriptFormat[] =
+ "(function(){ "
+ " var input = prompt(\"%@\");"
+ " if (input != null) {"
+ " document.body.innerHTML = input;"
+ " } else {"
+ " document.body.innerHTML = \"%@\";"
+ " }"
+ "})();";
+NSString* GetJavaScriptPromptTestScript() {
+ return [NSString stringWithFormat:@(kJavaScriptPromptTestScriptFormat),
+ @(kPromptMessage),
+ @(kPromptResultBodyCancelled)];
+}
+
+// Script to inject that will show a JavaScript alert in a loop 20 times, then
+// reset the document's HTML to |kAlertLoopFinishedText|.
+const char kAlertLoopFinishedText[] = "Loop Finished";
+const char kJavaScriptAlertLoopScriptFormat[] =
+ "(function(){ "
+ " for (i = 0; i < 20; ++i) {"
+ " alert(\"ALERT TEXT\");"
+ " }"
+ " document.body.innerHTML = \"%@\";"
+ "})();";
+NSString* GetJavaScriptAlertLoopScript() {
+ return [NSString stringWithFormat:@(kJavaScriptAlertLoopScriptFormat),
+ @(kAlertLoopFinishedText)];
+}
+
+// Returns the message for a JavaScript alert with |type|.
+NSString* GetMessageForAlertWithType(JavaScriptAlertType type) {
+ switch (type) {
+ case JavaScriptAlertType::ALERT:
+ return @(kAlertMessage);
+ case JavaScriptAlertType::CONFIRMATION:
+ return @(kConfirmationMessage);
+ case JavaScriptAlertType::PROMPT:
+ return @(kPromptMessage);
+ }
+ GREYFail(@"JavascriptAlertType not recognized.");
+ return nil;
+}
+
+// Returns the script to show a JavaScript alert with |type|.
+NSString* GetScriptForAlertWithType(JavaScriptAlertType type) {
+ switch (type) {
+ case JavaScriptAlertType::ALERT:
+ return GetJavaScriptAlertTestScript();
+ case JavaScriptAlertType::CONFIRMATION:
+ return GetJavaScriptConfirmationTestScript();
+ case JavaScriptAlertType::PROMPT:
+ return GetJavaScriptPromptTestScript();
+ }
+ GREYFail(@"JavascriptAlertType not recognized.");
+ return nil;
+}
+
+// Const for an http server that returns a blank document.
+const char* kJavaScriptTestURL = "http://jsalerts";
+const char* kJavaScriptTestResponse =
+ "<!DOCTYPE html><html><body></body></html>";
+
+// Waits until |string| is displayed on the web view.
+void WaitForWebDisplay(const std::string& string) {
+ id<GREYMatcher> response1Matcher =
+ chrome_test_util::webViewContainingText(string);
+ [[EarlGrey selectElementWithMatcher:response1Matcher]
+ assertWithMatcher:grey_notNil()];
+}
+
+// Display the javascript alert.
+void DisplayJavaScriptAlert(JavaScriptAlertType type) {
+ // Get the WebController.
+ web::WebState* webState = chrome_test_util::GetCurrentWebState();
+
+ // Evaluate JavaScript.
+ NSString* script = GetScriptForAlertWithType(type);
+ webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
+}
+
+// Assert that the javascript alert has been presented.
+void WaitForAlertToBeShown(NSString* alert_label) {
+ // Wait for the alert to be shown by trying to get the alert title.
+ ConditionBlock condition = ^{
+ NSError* error = nil;
+ id<GREYMatcher> titleLabel =
+ chrome_test_util::staticTextWithAccessibilityLabel(alert_label);
+ [[EarlGrey selectElementWithMatcher:titleLabel]
+ assertWithMatcher:grey_notNil()
+ error:&error];
+ return !error;
+ };
+ GREYAssert(testing::WaitUntilConditionOrTimeout(
+ testing::kWaitForJSCompletionTimeout, condition),
+ @"Alert with title was not present: %@", alert_label);
+}
+
+void WaitForJavaScripDialogToBeShown() {
+ NSString* alert_label = [DialogPresenter
+ localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
+ kJavaScriptTestURL)];
+ WaitForAlertToBeShown(alert_label);
+}
+
+// Injects JavaScript to show a dialog with |type|, verifying that it was
+// properly displayed.
+void ShowJavaScriptDialog(JavaScriptAlertType type) {
+ DisplayJavaScriptAlert(type);
+
+ WaitForJavaScripDialogToBeShown();
+
+ // Check the message of the alert.
+ id<GREYMatcher> messageLabel =
+ chrome_test_util::staticTextWithAccessibilityLabel(
+ GetMessageForAlertWithType(type));
+ [[EarlGrey selectElementWithMatcher:messageLabel]
+ assertWithMatcher:grey_notNil()];
+}
+
+// Assert no javascript alert is visible.
+void AssertJavaScriptAlertNotPresent() {
+ ConditionBlock condition = ^{
+ NSError* error = nil;
+ NSString* alertLabel = [DialogPresenter
+ localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
+ kJavaScriptTestURL)];
+ id<GREYMatcher> titleLabel =
+ chrome_test_util::staticTextWithAccessibilityLabel(alertLabel);
+ [[EarlGrey selectElementWithMatcher:titleLabel] assertWithMatcher:grey_nil()
+ error:&error];
+ return !error;
+ };
+
+ GREYAssert(testing::WaitUntilConditionOrTimeout(
+ testing::kWaitForJSCompletionTimeout, condition),
+ @"Javascript alert title was still present");
+}
+
+// Types |input| in the prompt.
+void TypeInPrompt(NSString* input) {
+ [[[EarlGrey selectElementWithMatcher:
+ grey_accessibilityID(
+ kJavaScriptDialogTextFieldAccessibiltyIdentifier)]
+ assertWithMatcher:grey_sufficientlyVisible()] performAction:grey_tap()];
+ [[EarlGrey selectElementWithMatcher:
+ grey_accessibilityID(
+ kJavaScriptDialogTextFieldAccessibiltyIdentifier)]
+ performAction:grey_typeText(input)];
+}
+
+void TapOK() {
+ id<GREYMatcher> ok_button =
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_OK);
+ [[EarlGrey selectElementWithMatcher:ok_button] performAction:grey_tap()];
+}
+
+void TapCancel() {
+ id<GREYMatcher> cancel_button =
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_CANCEL);
+ [[EarlGrey selectElementWithMatcher:cancel_button] performAction:grey_tap()];
+}
+
+void TapSuppressDialogsButton() {
+ id<GREYMatcher> suppress_dialogs_button =
+ chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT);
+ [[EarlGrey selectElementWithMatcher:suppress_dialogs_button]
+ performAction:grey_tap()];
+}
+
+} // namespace
+
+@interface JavaScriptDialogTestCase : ChromeTestCase {
+ GURL _URL;
+}
+
+@end
+
+@implementation JavaScriptDialogTestCase
+
+- (void)setUp {
+ [super setUp];
+ _URL = web::test::HttpServer::MakeUrl(kJavaScriptTestURL);
+ std::map<GURL, std::string> responses;
+ responses[web::test::HttpServer::MakeUrl(kJavaScriptTestURL)] =
+ kJavaScriptTestResponse;
+ web::test::SetUpSimpleHttpServer(responses);
+
+ [ChromeEarlGrey loadURL:_URL];
+ id<GREYMatcher> response2Matcher =
+ chrome_test_util::webViewContainingText(std::string(""));
+ [[EarlGrey selectElementWithMatcher:response2Matcher]
+ assertWithMatcher:grey_notNil()];
+}
+
+- (void)tearDown {
+ NSError* errorOK = nil;
+ NSError* errorCancel = nil;
+
+ // Dismiss JavaScript alert by tapping Cancel.
+ id<GREYMatcher> CancelButton =
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_CANCEL);
+ [[EarlGrey selectElementWithMatcher:CancelButton] performAction:grey_tap()
+ error:&errorCancel];
+ // Dismiss JavaScript alert by tapping OK.
+ id<GREYMatcher> OKButton =
+ chrome_test_util::buttonWithAccessibilityLabelId(IDS_OK);
+ [[EarlGrey selectElementWithMatcher:OKButton] performAction:grey_tap()
+ error:&errorOK];
+
+ if (!errorOK || !errorCancel) {
+ GREYFail(@"There are still alerts");
+ }
+ [super tearDown];
+}
+
+#pragma mark - Tests
+
+// Tests that an alert is shown, and that the completion block is called.
+- (void)testShowJavaScriptAlert {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show an alert.
+ ShowJavaScriptDialog(JavaScriptAlertType::ALERT);
+
+ // Tap the OK button.
+ TapOK();
+
+ // Wait for the html body to be reset to the correct value.
+ WaitForWebDisplay(kAlertResultBody);
+}
+
+// Tests that a confirmation dialog is shown, and that the completion block is
+// called with the correct value when the OK buton is tapped.
+- (void)testShowJavaScriptConfirmationOK {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show a confirmation dialog.
+ ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
+
+ // Tap the OK button.
+ TapOK();
+
+ // Wait for the html body to be reset to the correct value.
+ WaitForWebDisplay(kConfirmationResultBodyOK);
+}
+
+// Tests that a confirmation dialog is shown, and that the completion block is
+// called with the correct value when the Cancel buton is tapped.
+- (void)testShowJavaScriptConfirmationCancelled {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show a confirmation dialog.
+ ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
+
+ // Tap the Cancel button.
+ TapCancel();
+
+ // Wait for the html body to be reset to the correct value.
+ WaitForWebDisplay(kConfirmationResultBodyCancelled);
+}
+
+// Tests that a prompt dialog is shown, and that the completion block is called
+// with the correct value when the OK buton is tapped.
+- (void)testShowJavaScriptPromptOK {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show a prompt dialog.
+ ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
+
+ // Enter text into text field.
+ TypeInPrompt(@(kPromptTestUserInput));
+
+ // Tap the OK button.
+ TapOK();
+
+ // Wait for the html body to be reset to the input text.
+ WaitForWebDisplay(kPromptTestUserInput);
+}
+
+// Tests that a prompt dialog is shown, and that the completion block is called
+// with the correct value when the Cancel buton is tapped.
+- (void)testShowJavaScriptPromptCancelled {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show a prompt dialog.
+ ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
+
+ // Enter text into text field.
+ TypeInPrompt(@(kPromptTestUserInput));
+
+ // Tap the Cancel button.
+ TapCancel();
+
+ // Wait for the html body to be reset to the cancel text.
+ WaitForWebDisplay(kPromptResultBodyCancelled);
+}
+
+// Tests that JavaScript alerts that are shown in a loop can be suppressed.
+- (void)testShowJavaScriptAlertLoop {
+ // Evaluate JavaScript to show alerts in an endless loop.
+ web::WebState* webState = chrome_test_util::GetCurrentWebState();
+ NSString* script = GetJavaScriptAlertLoopScript();
+ webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
+ WaitForJavaScripDialogToBeShown();
+
+ // Tap the OK button and wait for another dialog to be shown.
+ TapOK();
+ WaitForJavaScripDialogToBeShown();
+
+ // Tap the suppress dialogs button.
+ TapSuppressDialogsButton();
+
+ // Wait for confirmation action sheet to be shown.
+ NSString* alertLabel =
+ l10n_util::GetNSString(IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION);
+ WaitForAlertToBeShown(alertLabel);
+
+ // Tap the suppress dialogs confirmation button.
+ TapSuppressDialogsButton();
+
+ // Wait for the html body to be reset to the loop finished text.
+ WaitForWebDisplay(kAlertLoopFinishedText);
+}
+
+// Tests to ensure crbug.com/658260 does not regress.
+// Tests that if an alert should be called when settings are displays, the alert
+// waits for the dismiss of the settings.
+- (void)testShowJavaScriptBehindSettings {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show settings.
+ [ChromeEarlGreyUI openToolsMenu];
+ [[EarlGrey
+ selectElementWithMatcher:grey_accessibilityID(kToolsMenuSettingsId)]
+ performAction:grey_tap()];
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::
+ staticTextWithAccessibilityLabelId(
+ IDS_IOS_SETTINGS_TITLE)]
+ assertWithMatcher:grey_sufficientlyVisible()];
+
+ // Show an alert.
+ DisplayJavaScriptAlert(JavaScriptAlertType::ALERT);
+
+ // Make sure the alert is not present.
+ AssertJavaScriptAlertNotPresent();
+
+ // Close the settings.
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)]
+ performAction:grey_tap()];
+
+ // Make sure the alert is present.
+ WaitForJavaScripDialogToBeShown();
+
+ // Tap the OK button.
+ TapOK();
+
+ // Wait for the html body to be reset to the correct value.
+ WaitForWebDisplay(kAlertResultBody);
+}
+
+// Tests that an alert is presented after displaying the share menu.
+- (void)testShowJavaScriptAfterShareMenu {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+ EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+ @"alerts would prevent app alerts to present "
+ @"correctly.");
+#endif
+
+ // Show the share menu.
+ if (!IsIPadIdiom())
+ [ChromeEarlGreyUI openToolsMenu];
+
+ NSString* shareLabel = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_SHARE);
+ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(shareLabel)]
+ performAction:grey_tap()];
+
+ // Copy URL, dismissing the share menu.
+ id<GREYMatcher> printButton =
+ grey_allOf(grey_accessibilityLabel(@"Copy"),
+ grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
+ [[EarlGrey selectElementWithMatcher:printButton] performAction:grey_tap()];
+
+ // Show an alert and assert it is present.
+ ShowJavaScriptDialog(JavaScriptAlertType::ALERT);
+
+ // Tap the OK button.
+ TapOK();
+
+ // Wait for the html body to be reset to the correct value.
+ WaitForWebDisplay(kAlertResultBody);
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698