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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <EarlGrey/EarlGrey.h>
6 #import <UIKit/UIKit.h>
7 #import <XCTest/XCTest.h>
8
9 #import "base/strings/sys_string_conversions.h"
10 #include "components/strings/grit/components_strings.h"
11 #import "ios/chrome/browser/ui/dialogs/dialog_presenter.h"
12 #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
13 #include "ios/chrome/browser/ui/ui_util.h"
14 #include "ios/chrome/grit/ios_strings.h"
15 #include "ios/chrome/test/app/chrome_test_util.h"
16 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
17 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
18 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
19 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
20 #import "ios/testing/earl_grey/disabled_test_macros.h"
21 #import "ios/testing/wait_util.h"
22 #import "ios/web/public/test/http_server.h"
23 #import "ios/web/public/test/http_server_util.h"
24 #include "ios/web/public/web_state/web_state.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/l10n/l10n_util_mac.h"
27 #import "url/gurl.h"
28
29 #if !defined(__has_feature) || !__has_feature(objc_arc)
30 #error "This file requires ARC support."
31 #endif
32
33 namespace {
34
35 // Enum specifying different types of JavaScript alerts:
36 // - JavaScriptAlertType::ALERT - Dialog with only one OK button.
37 // - JavaScriptAlertType::CONFIRMATION - Dialog with OK and Cancel button.
38 // - JavaScriptAlertType::PROMPT - Dialog with OK button, cancel button, and
39 // a text field.
40 enum class JavaScriptAlertType : NSUInteger { ALERT, CONFIRMATION, PROMPT };
41
42 // Script to inject that will show an alert. The document's body will be reset
43 // to |kAlertResultBody| after the dialog is dismissed.
44 const char kAlertMessage[] = "This is a JavaScript alert.";
45 const char kAlertResultBody[] = "JAVASCRIPT ALERT WAS DISMISSED";
46 const char kJavaScriptAlertTestScriptFormat[] =
47 "(function(){ "
48 " alert(\"%@\");"
49 " document.body.innerHTML = \"%@\";"
50 "})();";
51 NSString* GetJavaScriptAlertTestScript() {
52 return [NSString stringWithFormat:@(kJavaScriptAlertTestScriptFormat),
53 @(kAlertMessage), @(kAlertResultBody)];
54 }
55
56 // Script to inject that will show a confirmation dialog. The document's body
57 // will be reset to |kConfirmationResultBodyOK| or
58 // |kConfirmationResultBodyCancelled| depending on whether the OK or Cancel
59 // button was tapped.
60 const char kConfirmationMessage[] = "This is a JavaScript confirmation.";
61 const char kConfirmationResultBodyOK[] = "Okay";
62 const char kConfirmationResultBodyCancelled[] = "Cancelled";
63 const char kJavaScriptConfirmationScriptFormat[] =
64 "(function(){ "
65 " if (confirm(\"%@\") == true) {"
66 " document.body.innerHTML = \"%@\";"
67 " } else {"
68 " document.body.innerHTML = \"%@\";"
69 " }"
70 "})();";
71 NSString* GetJavaScriptConfirmationTestScript() {
72 return [NSString stringWithFormat:@(kJavaScriptConfirmationScriptFormat),
73 @(kConfirmationMessage),
74 @(kConfirmationResultBodyOK),
75 @(kConfirmationResultBodyCancelled)];
76 }
77
78 // Script to inject that will show a prompt dialog. The document's body will be
79 // reset to |kPromptResultBodyCancelled| or |kPromptTestUserInput| depending on
80 // whether the OK or Cancel button was tapped.
81 const char kPromptMessage[] = "This is a JavaScript prompt.";
82 const char kPromptResultBodyCancelled[] = "Cancelled";
83 const char kPromptTestUserInput[] = "test";
84 const char kJavaScriptPromptTestScriptFormat[] =
85 "(function(){ "
86 " var input = prompt(\"%@\");"
87 " if (input != null) {"
88 " document.body.innerHTML = input;"
89 " } else {"
90 " document.body.innerHTML = \"%@\";"
91 " }"
92 "})();";
93 NSString* GetJavaScriptPromptTestScript() {
94 return [NSString stringWithFormat:@(kJavaScriptPromptTestScriptFormat),
95 @(kPromptMessage),
96 @(kPromptResultBodyCancelled)];
97 }
98
99 // Script to inject that will show a JavaScript alert in a loop 20 times, then
100 // reset the document's HTML to |kAlertLoopFinishedText|.
101 const char kAlertLoopFinishedText[] = "Loop Finished";
102 const char kJavaScriptAlertLoopScriptFormat[] =
103 "(function(){ "
104 " for (i = 0; i < 20; ++i) {"
105 " alert(\"ALERT TEXT\");"
106 " }"
107 " document.body.innerHTML = \"%@\";"
108 "})();";
109 NSString* GetJavaScriptAlertLoopScript() {
110 return [NSString stringWithFormat:@(kJavaScriptAlertLoopScriptFormat),
111 @(kAlertLoopFinishedText)];
112 }
113
114 // Returns the message for a JavaScript alert with |type|.
115 NSString* GetMessageForAlertWithType(JavaScriptAlertType type) {
116 switch (type) {
117 case JavaScriptAlertType::ALERT:
118 return @(kAlertMessage);
119 case JavaScriptAlertType::CONFIRMATION:
120 return @(kConfirmationMessage);
121 case JavaScriptAlertType::PROMPT:
122 return @(kPromptMessage);
123 }
124 GREYFail(@"JavascriptAlertType not recognized.");
125 return nil;
126 }
127
128 // Returns the script to show a JavaScript alert with |type|.
129 NSString* GetScriptForAlertWithType(JavaScriptAlertType type) {
130 switch (type) {
131 case JavaScriptAlertType::ALERT:
132 return GetJavaScriptAlertTestScript();
133 case JavaScriptAlertType::CONFIRMATION:
134 return GetJavaScriptConfirmationTestScript();
135 case JavaScriptAlertType::PROMPT:
136 return GetJavaScriptPromptTestScript();
137 }
138 GREYFail(@"JavascriptAlertType not recognized.");
139 return nil;
140 }
141
142 // Const for an http server that returns a blank document.
143 const char* kJavaScriptTestURL = "http://jsalerts";
144 const char* kJavaScriptTestResponse =
145 "<!DOCTYPE html><html><body></body></html>";
146
147 // Waits until |string| is displayed on the web view.
148 void WaitForWebDisplay(const std::string& string) {
149 id<GREYMatcher> response1Matcher =
150 chrome_test_util::webViewContainingText(string);
151 [[EarlGrey selectElementWithMatcher:response1Matcher]
152 assertWithMatcher:grey_notNil()];
153 }
154
155 // Display the javascript alert.
156 void DisplayJavaScriptAlert(JavaScriptAlertType type) {
157 // Get the WebController.
158 web::WebState* webState = chrome_test_util::GetCurrentWebState();
159
160 // Evaluate JavaScript.
161 NSString* script = GetScriptForAlertWithType(type);
162 webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
163 }
164
165 // Assert that the javascript alert has been presented.
166 void WaitForAlertToBeShown(NSString* alert_label) {
167 // Wait for the alert to be shown by trying to get the alert title.
168 ConditionBlock condition = ^{
169 NSError* error = nil;
170 id<GREYMatcher> titleLabel =
171 chrome_test_util::staticTextWithAccessibilityLabel(alert_label);
172 [[EarlGrey selectElementWithMatcher:titleLabel]
173 assertWithMatcher:grey_notNil()
174 error:&error];
175 return !error;
176 };
177 GREYAssert(testing::WaitUntilConditionOrTimeout(
178 testing::kWaitForJSCompletionTimeout, condition),
179 @"Alert with title was not present: %@", alert_label);
180 }
181
182 void WaitForJavaScripDialogToBeShown() {
183 NSString* alert_label = [DialogPresenter
184 localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
185 kJavaScriptTestURL)];
186 WaitForAlertToBeShown(alert_label);
187 }
188
189 // Injects JavaScript to show a dialog with |type|, verifying that it was
190 // properly displayed.
191 void ShowJavaScriptDialog(JavaScriptAlertType type) {
192 DisplayJavaScriptAlert(type);
193
194 WaitForJavaScripDialogToBeShown();
195
196 // Check the message of the alert.
197 id<GREYMatcher> messageLabel =
198 chrome_test_util::staticTextWithAccessibilityLabel(
199 GetMessageForAlertWithType(type));
200 [[EarlGrey selectElementWithMatcher:messageLabel]
201 assertWithMatcher:grey_notNil()];
202 }
203
204 // Assert no javascript alert is visible.
205 void AssertJavaScriptAlertNotPresent() {
206 ConditionBlock condition = ^{
207 NSError* error = nil;
208 NSString* alertLabel = [DialogPresenter
209 localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
210 kJavaScriptTestURL)];
211 id<GREYMatcher> titleLabel =
212 chrome_test_util::staticTextWithAccessibilityLabel(alertLabel);
213 [[EarlGrey selectElementWithMatcher:titleLabel] assertWithMatcher:grey_nil()
214 error:&error];
215 return !error;
216 };
217
218 GREYAssert(testing::WaitUntilConditionOrTimeout(
219 testing::kWaitForJSCompletionTimeout, condition),
220 @"Javascript alert title was still present");
221 }
222
223 // Types |input| in the prompt.
224 void TypeInPrompt(NSString* input) {
225 [[[EarlGrey selectElementWithMatcher:
226 grey_accessibilityID(
227 kJavaScriptDialogTextFieldAccessibiltyIdentifier)]
228 assertWithMatcher:grey_sufficientlyVisible()] performAction:grey_tap()];
229 [[EarlGrey selectElementWithMatcher:
230 grey_accessibilityID(
231 kJavaScriptDialogTextFieldAccessibiltyIdentifier)]
232 performAction:grey_typeText(input)];
233 }
234
235 void TapOK() {
236 id<GREYMatcher> ok_button =
237 chrome_test_util::buttonWithAccessibilityLabelId(IDS_OK);
238 [[EarlGrey selectElementWithMatcher:ok_button] performAction:grey_tap()];
239 }
240
241 void TapCancel() {
242 id<GREYMatcher> cancel_button =
243 chrome_test_util::buttonWithAccessibilityLabelId(IDS_CANCEL);
244 [[EarlGrey selectElementWithMatcher:cancel_button] performAction:grey_tap()];
245 }
246
247 void TapSuppressDialogsButton() {
248 id<GREYMatcher> suppress_dialogs_button =
249 chrome_test_util::buttonWithAccessibilityLabelId(
250 IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT);
251 [[EarlGrey selectElementWithMatcher:suppress_dialogs_button]
252 performAction:grey_tap()];
253 }
254
255 } // namespace
256
257 @interface JavaScriptDialogTestCase : ChromeTestCase {
258 GURL _URL;
259 }
260
261 @end
262
263 @implementation JavaScriptDialogTestCase
264
265 - (void)setUp {
266 [super setUp];
267 _URL = web::test::HttpServer::MakeUrl(kJavaScriptTestURL);
268 std::map<GURL, std::string> responses;
269 responses[web::test::HttpServer::MakeUrl(kJavaScriptTestURL)] =
270 kJavaScriptTestResponse;
271 web::test::SetUpSimpleHttpServer(responses);
272
273 [ChromeEarlGrey loadURL:_URL];
274 id<GREYMatcher> response2Matcher =
275 chrome_test_util::webViewContainingText(std::string(""));
276 [[EarlGrey selectElementWithMatcher:response2Matcher]
277 assertWithMatcher:grey_notNil()];
278 }
279
280 - (void)tearDown {
281 NSError* errorOK = nil;
282 NSError* errorCancel = nil;
283
284 // Dismiss JavaScript alert by tapping Cancel.
285 id<GREYMatcher> CancelButton =
286 chrome_test_util::buttonWithAccessibilityLabelId(IDS_CANCEL);
287 [[EarlGrey selectElementWithMatcher:CancelButton] performAction:grey_tap()
288 error:&errorCancel];
289 // Dismiss JavaScript alert by tapping OK.
290 id<GREYMatcher> OKButton =
291 chrome_test_util::buttonWithAccessibilityLabelId(IDS_OK);
292 [[EarlGrey selectElementWithMatcher:OKButton] performAction:grey_tap()
293 error:&errorOK];
294
295 if (!errorOK || !errorCancel) {
296 GREYFail(@"There are still alerts");
297 }
298 [super tearDown];
299 }
300
301 #pragma mark - Tests
302
303 // Tests that an alert is shown, and that the completion block is called.
304 - (void)testShowJavaScriptAlert {
305 // TODO(crbug.com/663026): Reenable the test for devices.
306 #if !TARGET_IPHONE_SIMULATOR
307 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
308 @"alerts would prevent app alerts to present "
309 @"correctly.");
310 #endif
311
312 // Show an alert.
313 ShowJavaScriptDialog(JavaScriptAlertType::ALERT);
314
315 // Tap the OK button.
316 TapOK();
317
318 // Wait for the html body to be reset to the correct value.
319 WaitForWebDisplay(kAlertResultBody);
320 }
321
322 // Tests that a confirmation dialog is shown, and that the completion block is
323 // called with the correct value when the OK buton is tapped.
324 - (void)testShowJavaScriptConfirmationOK {
325 // TODO(crbug.com/663026): Reenable the test for devices.
326 #if !TARGET_IPHONE_SIMULATOR
327 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
328 @"alerts would prevent app alerts to present "
329 @"correctly.");
330 #endif
331
332 // Show a confirmation dialog.
333 ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
334
335 // Tap the OK button.
336 TapOK();
337
338 // Wait for the html body to be reset to the correct value.
339 WaitForWebDisplay(kConfirmationResultBodyOK);
340 }
341
342 // Tests that a confirmation dialog is shown, and that the completion block is
343 // called with the correct value when the Cancel buton is tapped.
344 - (void)testShowJavaScriptConfirmationCancelled {
345 // TODO(crbug.com/663026): Reenable the test for devices.
346 #if !TARGET_IPHONE_SIMULATOR
347 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
348 @"alerts would prevent app alerts to present "
349 @"correctly.");
350 #endif
351
352 // Show a confirmation dialog.
353 ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
354
355 // Tap the Cancel button.
356 TapCancel();
357
358 // Wait for the html body to be reset to the correct value.
359 WaitForWebDisplay(kConfirmationResultBodyCancelled);
360 }
361
362 // Tests that a prompt dialog is shown, and that the completion block is called
363 // with the correct value when the OK buton is tapped.
364 - (void)testShowJavaScriptPromptOK {
365 // TODO(crbug.com/663026): Reenable the test for devices.
366 #if !TARGET_IPHONE_SIMULATOR
367 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
368 @"alerts would prevent app alerts to present "
369 @"correctly.");
370 #endif
371
372 // Show a prompt dialog.
373 ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
374
375 // Enter text into text field.
376 TypeInPrompt(@(kPromptTestUserInput));
377
378 // Tap the OK button.
379 TapOK();
380
381 // Wait for the html body to be reset to the input text.
382 WaitForWebDisplay(kPromptTestUserInput);
383 }
384
385 // Tests that a prompt dialog is shown, and that the completion block is called
386 // with the correct value when the Cancel buton is tapped.
387 - (void)testShowJavaScriptPromptCancelled {
388 // TODO(crbug.com/663026): Reenable the test for devices.
389 #if !TARGET_IPHONE_SIMULATOR
390 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
391 @"alerts would prevent app alerts to present "
392 @"correctly.");
393 #endif
394
395 // Show a prompt dialog.
396 ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
397
398 // Enter text into text field.
399 TypeInPrompt(@(kPromptTestUserInput));
400
401 // Tap the Cancel button.
402 TapCancel();
403
404 // Wait for the html body to be reset to the cancel text.
405 WaitForWebDisplay(kPromptResultBodyCancelled);
406 }
407
408 // Tests that JavaScript alerts that are shown in a loop can be suppressed.
409 - (void)testShowJavaScriptAlertLoop {
410 // Evaluate JavaScript to show alerts in an endless loop.
411 web::WebState* webState = chrome_test_util::GetCurrentWebState();
412 NSString* script = GetJavaScriptAlertLoopScript();
413 webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
414 WaitForJavaScripDialogToBeShown();
415
416 // Tap the OK button and wait for another dialog to be shown.
417 TapOK();
418 WaitForJavaScripDialogToBeShown();
419
420 // Tap the suppress dialogs button.
421 TapSuppressDialogsButton();
422
423 // Wait for confirmation action sheet to be shown.
424 NSString* alertLabel =
425 l10n_util::GetNSString(IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION);
426 WaitForAlertToBeShown(alertLabel);
427
428 // Tap the suppress dialogs confirmation button.
429 TapSuppressDialogsButton();
430
431 // Wait for the html body to be reset to the loop finished text.
432 WaitForWebDisplay(kAlertLoopFinishedText);
433 }
434
435 // Tests to ensure crbug.com/658260 does not regress.
436 // Tests that if an alert should be called when settings are displays, the alert
437 // waits for the dismiss of the settings.
438 - (void)testShowJavaScriptBehindSettings {
439 // TODO(crbug.com/663026): Reenable the test for devices.
440 #if !TARGET_IPHONE_SIMULATOR
441 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
442 @"alerts would prevent app alerts to present "
443 @"correctly.");
444 #endif
445
446 // Show settings.
447 [ChromeEarlGreyUI openToolsMenu];
448 [[EarlGrey
449 selectElementWithMatcher:grey_accessibilityID(kToolsMenuSettingsId)]
450 performAction:grey_tap()];
451 [[EarlGrey selectElementWithMatcher:chrome_test_util::
452 staticTextWithAccessibilityLabelId(
453 IDS_IOS_SETTINGS_TITLE)]
454 assertWithMatcher:grey_sufficientlyVisible()];
455
456 // Show an alert.
457 DisplayJavaScriptAlert(JavaScriptAlertType::ALERT);
458
459 // Make sure the alert is not present.
460 AssertJavaScriptAlertNotPresent();
461
462 // Close the settings.
463 [[EarlGrey
464 selectElementWithMatcher:chrome_test_util::buttonWithAccessibilityLabelId(
465 IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)]
466 performAction:grey_tap()];
467
468 // Make sure the alert is present.
469 WaitForJavaScripDialogToBeShown();
470
471 // Tap the OK button.
472 TapOK();
473
474 // Wait for the html body to be reset to the correct value.
475 WaitForWebDisplay(kAlertResultBody);
476 }
477
478 // Tests that an alert is presented after displaying the share menu.
479 - (void)testShowJavaScriptAfterShareMenu {
480 // TODO(crbug.com/663026): Reenable the test for devices.
481 #if !TARGET_IPHONE_SIMULATOR
482 EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
483 @"alerts would prevent app alerts to present "
484 @"correctly.");
485 #endif
486
487 // Show the share menu.
488 if (!IsIPadIdiom())
489 [ChromeEarlGreyUI openToolsMenu];
490
491 NSString* shareLabel = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_SHARE);
492 [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(shareLabel)]
493 performAction:grey_tap()];
494
495 // Copy URL, dismissing the share menu.
496 id<GREYMatcher> printButton =
497 grey_allOf(grey_accessibilityLabel(@"Copy"),
498 grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
499 [[EarlGrey selectElementWithMatcher:printButton] performAction:grey_tap()];
500
501 // Show an alert and assert it is present.
502 ShowJavaScriptDialog(JavaScriptAlertType::ALERT);
503
504 // Tap the OK button.
505 TapOK();
506
507 // Wait for the html body to be reset to the correct value.
508 WaitForWebDisplay(kAlertResultBody);
509 }
510
511 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698