Revert 285173 "Removed InProcessBrowserTest::CleanUpOnMainThread()"
[chromium-blink-merge.git] / chrome / browser / password_manager / password_manager_browsertest.cc
blob92a3e9fa749d11c65d1d44c55818761cb12de03d
1 // Copyright 2013 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.
5 #include <string>
7 #include "base/command_line.h"
8 #include "base/metrics/histogram_samples.h"
9 #include "base/metrics/statistics_recorder.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/infobars/infobar_service.h"
16 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
17 #include "chrome/browser/password_manager/password_store_factory.h"
18 #include "chrome/browser/password_manager/test_password_store_service.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/login/login_prompt.h"
21 #include "chrome/browser/ui/login/login_prompt_test_utils.h"
22 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/chrome_version_info.h"
25 #include "chrome/test/base/in_process_browser_test.h"
26 #include "chrome/test/base/test_switches.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "components/autofill/core/browser/autofill_test_utils.h"
29 #include "components/infobars/core/confirm_infobar_delegate.h"
30 #include "components/infobars/core/infobar.h"
31 #include "components/infobars/core/infobar_manager.h"
32 #include "components/password_manager/core/browser/test_password_store.h"
33 #include "components/password_manager/core/common/password_manager_switches.h"
34 #include "content/public/browser/navigation_controller.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/render_frame_host.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_observer.h"
40 #include "content/public/test/browser_test_utils.h"
41 #include "content/public/test/test_utils.h"
42 #include "net/test/embedded_test_server/embedded_test_server.h"
43 #include "net/test/embedded_test_server/http_request.h"
44 #include "net/test/embedded_test_server/http_response.h"
45 #include "net/url_request/test_url_fetcher_factory.h"
46 #include "testing/gmock/include/gmock/gmock.h"
47 #include "third_party/WebKit/public/web/WebInputEvent.h"
48 #include "ui/events/keycodes/keyboard_codes.h"
49 #include "ui/gfx/geometry/point.h"
52 // NavigationObserver ---------------------------------------------------------
54 namespace {
56 // Observer that waits for navigation to complete and for the password infobar
57 // to be shown.
58 class NavigationObserver : public content::WebContentsObserver {
59 public:
60 explicit NavigationObserver(content::WebContents* web_contents)
61 : content::WebContentsObserver(web_contents),
62 message_loop_runner_(new content::MessageLoopRunner) {}
64 virtual ~NavigationObserver() {}
66 // Normally Wait() will not return until a main frame navigation occurs.
67 // If a path is set, Wait() will return after this path has been seen,
68 // regardless of the frame that navigated. Useful for multi-frame pages.
69 void SetPathToWaitFor(const std::string& path) {
70 wait_for_path_ = path;
73 // content::WebContentsObserver:
74 virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
75 const GURL& validated_url) OVERRIDE {
76 if (!wait_for_path_.empty()) {
77 if (validated_url.path() == wait_for_path_)
78 message_loop_runner_->Quit();
79 } else if (!render_frame_host->GetParent()) {
80 message_loop_runner_->Quit();
84 void Wait() { message_loop_runner_->Run(); }
86 private:
87 std::string wait_for_path_;
88 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
90 DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
93 // Observes the save password prompt (bubble or infobar) for a specified
94 // WebContents, keeps track of whether or not it is currently shown, and allows
95 // accepting saving passwords through it.
96 class PromptObserver {
97 public:
98 virtual ~PromptObserver() {}
100 // Checks if the prompt is being currently shown.
101 virtual bool IsShowingPrompt() const = 0;
103 // Expecting that the prompt is shown, saves the password. Checks that the
104 // prompt is no longer visible afterwards.
105 void Accept() const {
106 EXPECT_TRUE(IsShowingPrompt());
107 AcceptImpl();
110 // Chooses the right implementation of PromptObserver and creates an instance
111 // of it.
112 static scoped_ptr<PromptObserver> Create(content::WebContents* web_contents);
114 protected:
115 PromptObserver() {}
117 // Accepts the password. The implementation can assume that the prompt is
118 // currently shown, but is required to verify that the prompt is eventually
119 // closed.
120 virtual void AcceptImpl() const = 0;
122 private:
123 DISALLOW_COPY_AND_ASSIGN(PromptObserver);
126 class InfoBarObserver : public PromptObserver,
127 public infobars::InfoBarManager::Observer {
128 public:
129 explicit InfoBarObserver(content::WebContents* web_contents)
130 : infobar_is_being_shown_(false),
131 infobar_service_(InfoBarService::FromWebContents(web_contents)) {
132 infobar_service_->AddObserver(this);
135 virtual ~InfoBarObserver() {
136 if (infobar_service_)
137 infobar_service_->RemoveObserver(this);
140 private:
141 // PromptObserver:
142 virtual bool IsShowingPrompt() const OVERRIDE {
143 return infobar_is_being_shown_;
146 virtual void AcceptImpl() const OVERRIDE {
147 EXPECT_EQ(1u, infobar_service_->infobar_count());
148 if (!infobar_service_->infobar_count())
149 return; // Let the test finish to gather possibly more diagnostics.
151 // ConfirmInfoBarDelegate::Accept returning true means the infobar is
152 // immediately closed. Checking the return value is preferred to testing
153 // IsShowingPrompt() here, for it avoids the delay until the closing
154 // notification is received.
155 EXPECT_TRUE(infobar_service_->infobar_at(0)
156 ->delegate()
157 ->AsConfirmInfoBarDelegate()
158 ->Accept());
161 // infobars::InfoBarManager::Observer:
162 virtual void OnInfoBarAdded(infobars::InfoBar* infobar) OVERRIDE {
163 infobar_is_being_shown_ = true;
166 virtual void OnInfoBarRemoved(infobars::InfoBar* infobar,
167 bool animate) OVERRIDE {
168 infobar_is_being_shown_ = false;
171 virtual void OnManagerShuttingDown(
172 infobars::InfoBarManager* manager) OVERRIDE {
173 ASSERT_EQ(infobar_service_, manager);
174 infobar_service_->RemoveObserver(this);
175 infobar_service_ = NULL;
178 bool infobar_is_being_shown_;
179 InfoBarService* infobar_service_;
181 DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
184 class BubbleObserver : public PromptObserver {
185 public:
186 explicit BubbleObserver(content::WebContents* web_contents)
187 : ui_controller_(
188 ManagePasswordsUIController::FromWebContents(web_contents)) {}
190 virtual ~BubbleObserver() {}
192 private:
193 // PromptObserver:
194 virtual bool IsShowingPrompt() const OVERRIDE {
195 return ui_controller_->PasswordPendingUserDecision();
198 virtual void AcceptImpl() const OVERRIDE {
199 ui_controller_->SavePassword();
200 EXPECT_FALSE(IsShowingPrompt());
203 ManagePasswordsUIController* const ui_controller_;
205 DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
208 // static
209 scoped_ptr<PromptObserver> PromptObserver::Create(
210 content::WebContents* web_contents) {
211 if (ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled()) {
212 return scoped_ptr<PromptObserver>(new BubbleObserver(web_contents));
213 } else {
214 return scoped_ptr<PromptObserver>(new InfoBarObserver(web_contents));
218 // Handles |request| to "/basic_auth". If "Authorization" header is present,
219 // responds with a non-empty HTTP 200 page (regardless of its value). Otherwise
220 // serves a Basic Auth challenge.
221 scoped_ptr<net::test_server::HttpResponse> HandleTestAuthRequest(
222 const net::test_server::HttpRequest& request) {
223 if (!StartsWithASCII(request.relative_url, "/basic_auth", true))
224 return scoped_ptr<net::test_server::HttpResponse>();
226 if (ContainsKey(request.headers, "Authorization")) {
227 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
228 new net::test_server::BasicHttpResponse);
229 http_response->set_code(net::HTTP_OK);
230 http_response->set_content("Success!");
231 return http_response.PassAs<net::test_server::HttpResponse>();
232 } else {
233 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
234 new net::test_server::BasicHttpResponse);
235 http_response->set_code(net::HTTP_UNAUTHORIZED);
236 http_response->AddCustomHeader("WWW-Authenticate",
237 "Basic realm=\"test realm\"");
238 return http_response.PassAs<net::test_server::HttpResponse>();
242 } // namespace
245 // PasswordManagerBrowserTest -------------------------------------------------
247 class PasswordManagerBrowserTest : public InProcessBrowserTest {
248 public:
249 PasswordManagerBrowserTest() {}
250 virtual ~PasswordManagerBrowserTest() {}
252 // InProcessBrowserTest:
253 virtual void SetUpOnMainThread() OVERRIDE {
254 // Use TestPasswordStore to remove a possible race. Normally the
255 // PasswordStore does its database manipulation on the DB thread, which
256 // creates a possible race during navigation. Specifically the
257 // PasswordManager will ignore any forms in a page if the load from the
258 // PasswordStore has not completed.
259 PasswordStoreFactory::GetInstance()->SetTestingFactory(
260 browser()->profile(), TestPasswordStoreService::Build);
261 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
262 ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
263 password_manager::switches::kEnableAutomaticPasswordSaving));
266 virtual void CleanUpOnMainThread() OVERRIDE {
267 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
268 InProcessBrowserTest::CleanUpOnMainThread();
271 protected:
272 content::WebContents* WebContents() {
273 return browser()->tab_strip_model()->GetActiveWebContents();
276 content::RenderViewHost* RenderViewHost() {
277 return WebContents()->GetRenderViewHost();
280 // Wrapper around ui_test_utils::NavigateToURL that waits until
281 // DidFinishLoad() fires. Normally this function returns after
282 // DidStopLoading(), which caused flakiness as the NavigationObserver
283 // would sometimes see the DidFinishLoad event from a previous navigation and
284 // return immediately.
285 void NavigateToFile(const std::string& path) {
286 NavigationObserver observer(WebContents());
287 GURL url = embedded_test_server()->GetURL(path);
288 ui_test_utils::NavigateToURL(browser(), url);
289 observer.Wait();
292 // Waits until the "value" attribute of the HTML element with |element_id| is
293 // equal to |expected_value|. If the current value is not as expected, this
294 // waits until the "change" event is fired for the element. This also
295 // guarantees that once the real value matches the expected, the JavaScript
296 // event loop is spun to allow all other possible events to take place.
297 void WaitForElementValue(const std::string& element_id,
298 const std::string& expected_value);
299 // Checks that the current "value" attribute of the HTML element with
300 // |element_id| is equal to |expected_value|.
301 void CheckElementValue(const std::string& element_id,
302 const std::string& expected_value);
304 private:
305 DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
308 void PasswordManagerBrowserTest::WaitForElementValue(
309 const std::string& element_id,
310 const std::string& expected_value) {
311 enum ReturnCodes { // Possible results of the JavaScript code.
312 RETURN_CODE_OK,
313 RETURN_CODE_NO_ELEMENT,
314 RETURN_CODE_WRONG_VALUE,
315 RETURN_CODE_INVALID,
317 const std::string value_check_function = base::StringPrintf(
318 "function valueCheck() {"
319 " var element = document.getElementById('%s');"
320 " return element && element.value == '%s';"
321 "}",
322 element_id.c_str(),
323 expected_value.c_str());
324 const std::string script =
325 value_check_function +
326 base::StringPrintf(
327 "if (valueCheck()) {"
328 " /* Spin the event loop with setTimeout. */"
329 " setTimeout(window.domAutomationController.send(%d), 0);"
330 "} else {"
331 " var element = document.getElementById('%s');"
332 " if (!element)"
333 " window.domAutomationController.send(%d);"
334 " element.onchange = function() {"
335 " if (valueCheck()) {"
336 " /* Spin the event loop with setTimeout. */"
337 " setTimeout(window.domAutomationController.send(%d), 0);"
338 " } else {"
339 " window.domAutomationController.send(%d);"
340 " }"
341 " };"
342 "}",
343 RETURN_CODE_OK,
344 element_id.c_str(),
345 RETURN_CODE_NO_ELEMENT,
346 RETURN_CODE_OK,
347 RETURN_CODE_WRONG_VALUE);
348 int return_value = RETURN_CODE_INVALID;
349 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
350 RenderViewHost(), script, &return_value));
351 EXPECT_EQ(RETURN_CODE_OK, return_value)
352 << "element_id = " << element_id
353 << ", expected_value = " << expected_value;
356 void PasswordManagerBrowserTest::CheckElementValue(
357 const std::string& element_id,
358 const std::string& expected_value) {
359 const std::string value_check_script = base::StringPrintf(
360 "var element = document.getElementById('%s');"
361 "window.domAutomationController.send(element && element.value == '%s');",
362 element_id.c_str(),
363 expected_value.c_str());
364 bool return_value = false;
365 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
366 RenderViewHost(), value_check_script, &return_value));
367 EXPECT_TRUE(return_value) << "element_id = " << element_id
368 << ", expected_value = " << expected_value;
371 // Actual tests ---------------------------------------------------------------
372 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
373 PromptForNormalSubmit) {
374 NavigateToFile("/password/password_form.html");
376 // Fill a form and submit through a <input type="submit"> button. Nothing
377 // special.
378 NavigationObserver observer(WebContents());
379 scoped_ptr<PromptObserver> prompt_observer(
380 PromptObserver::Create(WebContents()));
381 std::string fill_and_submit =
382 "document.getElementById('username_field').value = 'temp';"
383 "document.getElementById('password_field').value = 'random';"
384 "document.getElementById('input_submit_button').click()";
385 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
386 observer.Wait();
387 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
390 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
391 PromptForSubmitWithInPageNavigation) {
392 NavigateToFile("/password/password_navigate_before_submit.html");
394 // Fill a form and submit through a <input type="submit"> button. Nothing
395 // special. The form does an in-page navigation before submitting.
396 NavigationObserver observer(WebContents());
397 scoped_ptr<PromptObserver> prompt_observer(
398 PromptObserver::Create(WebContents()));
399 std::string fill_and_submit =
400 "document.getElementById('username_field').value = 'temp';"
401 "document.getElementById('password_field').value = 'random';"
402 "document.getElementById('input_submit_button').click()";
403 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
404 observer.Wait();
405 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
408 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
409 LoginSuccessWithUnrelatedForm) {
410 // Log in, see a form on the landing page. That form is not related to the
411 // login form (=has a different action), so we should offer saving the
412 // password.
413 NavigateToFile("/password/password_form.html");
415 NavigationObserver observer(WebContents());
416 scoped_ptr<PromptObserver> prompt_observer(
417 PromptObserver::Create(WebContents()));
418 std::string fill_and_submit =
419 "document.getElementById('username_unrelated').value = 'temp';"
420 "document.getElementById('password_unrelated').value = 'random';"
421 "document.getElementById('submit_unrelated').click()";
422 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
423 observer.Wait();
424 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
427 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, LoginFailed) {
428 // Log in, see a form on the landing page. That form is not related to the
429 // login form (=has a different action), so we should offer saving the
430 // password.
431 NavigateToFile("/password/password_form.html");
433 NavigationObserver observer(WebContents());
434 scoped_ptr<PromptObserver> prompt_observer(
435 PromptObserver::Create(WebContents()));
436 std::string fill_and_submit =
437 "document.getElementById('username_failed').value = 'temp';"
438 "document.getElementById('password_failed').value = 'random';"
439 "document.getElementById('submit_failed').click()";
440 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
441 observer.Wait();
442 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
445 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
446 NavigateToFile("/password/password_form.html");
448 // Fill a form and submit through a <input type="submit"> button. The form
449 // points to a redirection page.
450 NavigationObserver observer(WebContents());
451 scoped_ptr<PromptObserver> prompt_observer(
452 PromptObserver::Create(WebContents()));
453 std::string fill_and_submit =
454 "document.getElementById('username_redirect').value = 'temp';"
455 "document.getElementById('password_redirect').value = 'random';"
456 "document.getElementById('submit_redirect').click()";
457 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
458 observer.Wait();
459 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
461 // The redirection page now redirects via Javascript. We check that the
462 // infobar stays.
463 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
464 "window.location.href = 'done.html';"));
465 observer.Wait();
466 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
469 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
470 PromptForSubmitUsingJavaScript) {
471 NavigateToFile("/password/password_form.html");
473 // Fill a form and submit using <button> that calls submit() on the form.
474 // This should work regardless of the type of element, as long as submit() is
475 // called.
476 NavigationObserver observer(WebContents());
477 scoped_ptr<PromptObserver> prompt_observer(
478 PromptObserver::Create(WebContents()));
479 std::string fill_and_submit =
480 "document.getElementById('username_field').value = 'temp';"
481 "document.getElementById('password_field').value = 'random';"
482 "document.getElementById('submit_button').click()";
483 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
484 observer.Wait();
485 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
488 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
489 // platforms.
490 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
491 DISABLED_PromptForDynamicForm) {
492 NavigateToFile("/password/dynamic_password_form.html");
494 // Fill the dynamic password form and submit.
495 NavigationObserver observer(WebContents());
496 scoped_ptr<PromptObserver> prompt_observer(
497 PromptObserver::Create(WebContents()));
498 std::string fill_and_submit =
499 "document.getElementById('create_form_button').click();"
500 "window.setTimeout(function() {"
501 " document.dynamic_form.username.value = 'tempro';"
502 " document.dynamic_form.password.value = 'random';"
503 " document.dynamic_form.submit();"
504 "}, 0)";
505 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
506 observer.Wait();
507 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
510 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
511 NavigateToFile("/password/password_form.html");
513 // Don't fill the password form, just navigate away. Shouldn't prompt.
514 NavigationObserver observer(WebContents());
515 scoped_ptr<PromptObserver> prompt_observer(
516 PromptObserver::Create(WebContents()));
517 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
518 "window.location.href = 'done.html';"));
519 observer.Wait();
520 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
523 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
524 NoPromptForSubFrameNavigation) {
525 NavigateToFile("/password/multi_frames.html");
527 // If you are filling out a password form in one frame and a different frame
528 // navigates, this should not trigger the infobar.
529 NavigationObserver observer(WebContents());
530 scoped_ptr<PromptObserver> prompt_observer(
531 PromptObserver::Create(WebContents()));
532 observer.SetPathToWaitFor("/password/done.html");
533 std::string fill =
534 "var first_frame = document.getElementById('first_frame');"
535 "var frame_doc = first_frame.contentDocument;"
536 "frame_doc.getElementById('username_field').value = 'temp';"
537 "frame_doc.getElementById('password_field').value = 'random';";
538 std::string navigate_frame =
539 "var second_iframe = document.getElementById('second_frame');"
540 "second_iframe.contentWindow.location.href = 'done.html';";
542 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
543 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
544 observer.Wait();
545 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
548 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
549 PromptAfterSubmitWithSubFrameNavigation) {
550 NavigateToFile("/password/multi_frames.html");
552 // Make sure that we prompt to save password even if a sub-frame navigation
553 // happens first.
554 NavigationObserver observer(WebContents());
555 scoped_ptr<PromptObserver> prompt_observer(
556 PromptObserver::Create(WebContents()));
557 observer.SetPathToWaitFor("/password/done.html");
558 std::string navigate_frame =
559 "var second_iframe = document.getElementById('second_frame');"
560 "second_iframe.contentWindow.location.href = 'other.html';";
561 std::string fill_and_submit =
562 "var first_frame = document.getElementById('first_frame');"
563 "var frame_doc = first_frame.contentDocument;"
564 "frame_doc.getElementById('username_field').value = 'temp';"
565 "frame_doc.getElementById('password_field').value = 'random';"
566 "frame_doc.getElementById('input_submit_button').click();";
568 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
569 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
570 observer.Wait();
571 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
574 IN_PROC_BROWSER_TEST_F(
575 PasswordManagerBrowserTest,
576 NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage) {
577 NavigateToFile("/password/multi_frames.html");
579 // Make sure that we don't prompt to save the password for a failed login
580 // from the main frame with multiple frames in the same page.
581 NavigationObserver observer(WebContents());
582 scoped_ptr<PromptObserver> prompt_observer(
583 PromptObserver::Create(WebContents()));
584 std::string fill_and_submit =
585 "document.getElementById('username_failed').value = 'temp';"
586 "document.getElementById('password_failed').value = 'random';"
587 "document.getElementById('submit_failed').click();";
589 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
590 observer.Wait();
591 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
594 IN_PROC_BROWSER_TEST_F(
595 PasswordManagerBrowserTest,
596 NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage) {
597 NavigateToFile("/password/multi_frames.html");
599 // Make sure that we don't prompt to save the password for a failed login
600 // from a sub-frame with multiple frames in the same page.
601 NavigationObserver observer(WebContents());
602 scoped_ptr<PromptObserver> prompt_observer(
603 PromptObserver::Create(WebContents()));
604 std::string fill_and_submit =
605 "var first_frame = document.getElementById('first_frame');"
606 "var frame_doc = first_frame.contentDocument;"
607 "frame_doc.getElementById('username_failed').value = 'temp';"
608 "frame_doc.getElementById('password_failed').value = 'random';"
609 "frame_doc.getElementById('submit_failed').click();"
610 "window.parent.location.href = 'multi_frames.html';";
612 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
613 observer.Wait();
614 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
617 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
618 #if defined(OS_WIN) && defined(USE_ASH)
619 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
620 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
621 return;
622 #endif
623 NavigateToFile("/password/password_xhr_submit.html");
625 // Verify that we show the save password prompt if a form returns false
626 // in its onsubmit handler but instead logs in/navigates via XHR.
627 // Note that calling 'submit()' on a form with javascript doesn't call
628 // the onsubmit handler, so we click the submit button instead.
629 NavigationObserver observer(WebContents());
630 scoped_ptr<PromptObserver> prompt_observer(
631 PromptObserver::Create(WebContents()));
632 std::string fill_and_submit =
633 "document.getElementById('username_field').value = 'temp';"
634 "document.getElementById('password_field').value = 'random';"
635 "document.getElementById('submit_button').click()";
636 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
637 observer.Wait();
638 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
641 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
642 PromptForXHRWithoutOnSubmit) {
643 NavigateToFile("/password/password_xhr_submit.html");
645 // Verify that if XHR navigation occurs and the form is properly filled out,
646 // we try and save the password even though onsubmit hasn't been called.
647 NavigationObserver observer(WebContents());
648 scoped_ptr<PromptObserver> prompt_observer(
649 PromptObserver::Create(WebContents()));
650 std::string fill_and_navigate =
651 "document.getElementById('username_field').value = 'temp';"
652 "document.getElementById('password_field').value = 'random';"
653 "send_xhr()";
654 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
655 observer.Wait();
656 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
659 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfLinkClicked) {
660 NavigateToFile("/password/password_form.html");
662 // Verify that if the user takes a direct action to leave the page, we don't
663 // prompt to save the password even if the form is already filled out.
664 NavigationObserver observer(WebContents());
665 scoped_ptr<PromptObserver> prompt_observer(
666 PromptObserver::Create(WebContents()));
667 std::string fill_and_click_link =
668 "document.getElementById('username_field').value = 'temp';"
669 "document.getElementById('password_field').value = 'random';"
670 "document.getElementById('link').click();";
671 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link));
672 observer.Wait();
673 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
676 // TODO(jam): http://crbug.com/350550
677 #if !defined(OS_WIN)
678 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
679 VerifyPasswordGenerationUpload) {
680 // Prevent Autofill requests from actually going over the wire.
681 net::TestURLFetcherFactory factory;
682 // Disable Autofill requesting access to AddressBook data. This causes
683 // the test to hang on Mac.
684 autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
686 // Visit a signup form.
687 NavigateToFile("/password/signup_form.html");
689 // Enter a password and save it.
690 NavigationObserver first_observer(WebContents());
691 scoped_ptr<PromptObserver> prompt_observer(
692 PromptObserver::Create(WebContents()));
693 std::string fill_and_submit =
694 "document.getElementById('other_info').value = 'stuff';"
695 "document.getElementById('username_field').value = 'my_username';"
696 "document.getElementById('password_field').value = 'password';"
697 "document.getElementById('input_submit_button').click()";
698 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
700 first_observer.Wait();
701 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
702 prompt_observer->Accept();
704 // Now navigate to a login form that has similar HTML markup.
705 NavigateToFile("/password/password_form.html");
707 // Simulate a user click to force an autofill of the form's DOM value, not
708 // just the suggested value.
709 content::SimulateMouseClick(
710 WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
712 // The form should be filled with the previously submitted username.
713 std::string get_username =
714 "window.domAutomationController.send("
715 "document.getElementById('username_field').value);";
716 std::string actual_username;
717 ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
718 get_username,
719 &actual_username));
720 ASSERT_EQ("my_username", actual_username);
722 // Submit the form and verify that there is no infobar (as the password
723 // has already been saved).
724 NavigationObserver second_observer(WebContents());
725 scoped_ptr<PromptObserver> second_prompt_observer(
726 PromptObserver::Create(WebContents()));
727 std::string submit_form =
728 "document.getElementById('input_submit_button').click()";
729 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form));
730 second_observer.Wait();
731 EXPECT_FALSE(second_prompt_observer->IsShowingPrompt());
733 // Verify that we sent a ping to Autofill saying that the original form
734 // was likely an account creation form since it has more than 2 text input
735 // fields and was used for the first time on a different form.
736 base::HistogramBase* upload_histogram =
737 base::StatisticsRecorder::FindHistogram(
738 "PasswordGeneration.UploadStarted");
739 ASSERT_TRUE(upload_histogram);
740 scoped_ptr<base::HistogramSamples> snapshot =
741 upload_histogram->SnapshotSamples();
742 EXPECT_EQ(0, snapshot->GetCount(0 /* failure */));
743 EXPECT_EQ(1, snapshot->GetCount(1 /* success */));
745 #endif
747 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
748 NavigateToFile("/password/password_submit_from_iframe.html");
750 // Submit a form in an iframe, then cause the whole page to navigate without a
751 // user gesture. We expect the save password prompt to be shown here, because
752 // some pages use such iframes for login forms.
753 NavigationObserver observer(WebContents());
754 scoped_ptr<PromptObserver> prompt_observer(
755 PromptObserver::Create(WebContents()));
756 std::string fill_and_submit =
757 "var iframe = document.getElementById('test_iframe');"
758 "var iframe_doc = iframe.contentDocument;"
759 "iframe_doc.getElementById('username_field').value = 'temp';"
760 "iframe_doc.getElementById('password_field').value = 'random';"
761 "iframe_doc.getElementById('submit_button').click()";
763 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
764 observer.Wait();
765 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
768 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
769 PromptForInputElementWithoutName) {
770 // Check that the prompt is shown for forms where input elements lack the
771 // "name" attribute but the "id" is present.
772 NavigateToFile("/password/password_form.html");
774 NavigationObserver observer(WebContents());
775 scoped_ptr<PromptObserver> prompt_observer(
776 PromptObserver::Create(WebContents()));
777 std::string fill_and_submit =
778 "document.getElementById('username_field_no_name').value = 'temp';"
779 "document.getElementById('password_field_no_name').value = 'random';"
780 "document.getElementById('input_submit_button_no_name').click()";
781 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
782 observer.Wait();
783 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
786 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
787 PromptForInputElementWithoutId) {
788 // Check that the prompt is shown for forms where input elements lack the
789 // "id" attribute but the "name" attribute is present.
790 NavigateToFile("/password/password_form.html");
792 NavigationObserver observer(WebContents());
793 scoped_ptr<PromptObserver> prompt_observer(
794 PromptObserver::Create(WebContents()));
795 std::string fill_and_submit =
796 "document.getElementsByName('username_field_no_id')[0].value = 'temp';"
797 "document.getElementsByName('password_field_no_id')[0].value = 'random';"
798 "document.getElementsByName('input_submit_button_no_id')[0].click()";
799 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
800 observer.Wait();
801 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
804 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
805 NoPromptForInputElementWithoutIdAndName) {
806 // Check that no prompt is shown for forms where the input fields lack both
807 // the "id" and the "name" attributes.
808 NavigateToFile("/password/password_form.html");
810 NavigationObserver observer(WebContents());
811 scoped_ptr<PromptObserver> prompt_observer(
812 PromptObserver::Create(WebContents()));
813 std::string fill_and_submit =
814 "var form = document.getElementById('testform_elements_no_id_no_name');"
815 "var username = form.children[0];"
816 "username.value = 'temp';"
817 "var password = form.children[1];"
818 "password.value = 'random';"
819 "form.children[2].click()"; // form.children[2] is the submit button.
820 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
821 observer.Wait();
822 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
825 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
826 NavigateToFile("/password/multi_frames.html");
828 NavigationObserver observer(WebContents());
829 // Make sure we save some password info from an iframe and then destroy it.
830 std::string save_and_remove =
831 "var first_frame = document.getElementById('first_frame');"
832 "var frame_doc = first_frame.contentDocument;"
833 "frame_doc.getElementById('username_field').value = 'temp';"
834 "frame_doc.getElementById('password_field').value = 'random';"
835 "frame_doc.getElementById('input_submit_button').click();"
836 "first_frame.parentNode.removeChild(first_frame);";
837 // Submit from the main frame, but without navigating through the onsubmit
838 // handler.
839 std::string navigate_frame =
840 "document.getElementById('username_field').value = 'temp';"
841 "document.getElementById('password_field').value = 'random';"
842 "document.getElementById('input_submit_button').click();"
843 "window.location.href = 'done.html';";
845 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), save_and_remove));
846 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
847 observer.Wait();
848 // The only thing we check here is that there is no use-after-free reported.
851 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PasswordValueAccessible) {
852 NavigateToFile("/password/form_and_link.html");
854 // Click on a link to open a new tab, then switch back to the first one.
855 EXPECT_EQ(1, browser()->tab_strip_model()->count());
856 std::string click =
857 "document.getElementById('testlink').click();";
858 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), click));
859 EXPECT_EQ(2, browser()->tab_strip_model()->count());
860 browser()->tab_strip_model()->ActivateTabAt(0, false);
862 // Fill in the credentials, and make sure they are saved.
863 NavigationObserver form_submit_observer(WebContents());
864 scoped_ptr<PromptObserver> prompt_observer(
865 PromptObserver::Create(WebContents()));
866 std::string fill_and_submit =
867 "document.getElementById('username_field').value = 'temp';"
868 "document.getElementById('password_field').value = 'random';"
869 "document.getElementById('input_submit_button').click();";
870 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
871 form_submit_observer.Wait();
872 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
873 prompt_observer->Accept();
875 // Reload the original page to have the saved credentials autofilled.
876 NavigationObserver reload_observer(WebContents());
877 NavigateToFile("/password/form_and_link.html");
878 reload_observer.Wait();
880 // Wait until the username is filled, to make sure autofill kicked in.
881 WaitForElementValue("username_field", "temp");
882 // Now check that the password is not accessible yet.
883 CheckElementValue("password_field", "");
884 // Let the user interact with the page.
885 content::SimulateMouseClickAt(
886 WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(1, 1));
887 // Wait until that interaction causes the password value to be revealed.
888 WaitForElementValue("password_field", "random");
889 // And check that after the side-effects of the interaction took place, the
890 // username value stays the same.
891 CheckElementValue("username_field", "temp");
894 // The following test is limited to Aura, because
895 // RenderWidgetHostViewGuest::ProcessAckedTouchEvent is, and
896 // ProcessAckedTouchEvent is what triggers the translation of touch events to
897 // gesture events.
898 #if defined(USE_AURA)
899 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
900 PasswordValueAccessibleOnSubmit) {
901 NavigateToFile("/password/form_and_link.html");
903 // Fill in the credentials, and make sure they are saved.
904 NavigationObserver form_submit_observer(WebContents());
905 scoped_ptr<PromptObserver> prompt_observer(
906 PromptObserver::Create(WebContents()));
907 std::string fill_and_submit =
908 "document.getElementById('username_field').value = 'temp';"
909 "document.getElementById('password_field').value = 'random_secret';"
910 "document.getElementById('input_submit_button').click();";
911 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
912 form_submit_observer.Wait();
913 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
914 prompt_observer->Accept();
916 // Reload the original page to have the saved credentials autofilled.
917 NavigationObserver reload_observer(WebContents());
918 NavigateToFile("/password/form_and_link.html");
919 reload_observer.Wait();
921 NavigationObserver submit_observer(WebContents());
922 // Submit the form via a tap on the submit button. The button is placed at 0,
923 // 100, and has height 300 and width 700.
924 content::SimulateTapAt(WebContents(), gfx::Point(350, 250));
925 submit_observer.Wait();
926 std::string query = WebContents()->GetURL().query();
927 EXPECT_NE(std::string::npos, query.find("random_secret")) << query;
929 #endif
931 // Test fix for crbug.com/338650.
932 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
933 DontPromptForPasswordFormWithDefaultValue) {
934 NavigateToFile("/password/password_form_with_default_value.html");
936 // Don't prompt if we navigate away even if there is a password value since
937 // it's not coming from the user.
938 NavigationObserver observer(WebContents());
939 scoped_ptr<PromptObserver> prompt_observer(
940 PromptObserver::Create(WebContents()));
941 NavigateToFile("/password/done.html");
942 observer.Wait();
943 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
946 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
947 PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
948 NavigateToFile("/password/password_form.html");
950 // Fill a form and submit through a <input type="submit"> button.
951 NavigationObserver observer(WebContents());
952 scoped_ptr<PromptObserver> prompt_observer(
953 PromptObserver::Create(WebContents()));
954 std::string fill_and_submit =
955 "document.getElementById('username_field').value = 'temp';"
956 "document.getElementById('password_field').value = 'random';"
957 "document.getElementById('input_submit_button').click()";
958 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
959 observer.Wait();
960 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
963 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
964 DontPromptWhenEnableAutomaticPasswordSavingSwitchIsSet) {
965 password_manager::TestPasswordStore* password_store =
966 static_cast<password_manager::TestPasswordStore*>(
967 PasswordStoreFactory::GetForProfile(browser()->profile(),
968 Profile::IMPLICIT_ACCESS).get());
970 EXPECT_TRUE(password_store->IsEmpty());
972 NavigateToFile("/password/password_form.html");
974 // Add the enable-automatic-password-saving switch.
975 CommandLine::ForCurrentProcess()->AppendSwitch(
976 password_manager::switches::kEnableAutomaticPasswordSaving);
978 // Fill a form and submit through a <input type="submit"> button.
979 NavigationObserver observer(WebContents());
980 scoped_ptr<PromptObserver> prompt_observer(
981 PromptObserver::Create(WebContents()));
982 // Make sure that the only passwords saved are the auto-saved ones.
983 std::string fill_and_submit =
984 "document.getElementById('username_field').value = 'temp';"
985 "document.getElementById('password_field').value = 'random';"
986 "document.getElementById('input_submit_button').click()";
987 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
988 observer.Wait();
989 if (chrome::VersionInfo::GetChannel() ==
990 chrome::VersionInfo::CHANNEL_UNKNOWN) {
991 // Passwords getting auto-saved, no prompt.
992 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
993 EXPECT_FALSE(password_store->IsEmpty());
994 } else {
995 // Prompt shown, and no passwords saved automatically.
996 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
997 EXPECT_TRUE(password_store->IsEmpty());
1001 // Test fix for crbug.com/368690.
1002 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
1003 NavigateToFile("/password/password_form.html");
1005 std::string fill =
1006 "document.getElementById('username_redirect').value = 'temp';"
1007 "document.getElementById('password_redirect').value = 'random';";
1008 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
1010 NavigationObserver observer(WebContents());
1011 scoped_ptr<PromptObserver> prompt_observer(
1012 PromptObserver::Create(WebContents()));
1013 GURL url = embedded_test_server()->GetURL("/password/password_form.html");
1014 chrome::NavigateParams params(browser(), url,
1015 content::PAGE_TRANSITION_RELOAD);
1016 ui_test_utils::NavigateToURL(&params);
1017 observer.Wait();
1018 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1021 // Test that if a form gets dynamically added between the form parsing and
1022 // rendering, and while the main frame still loads, it still is registered, and
1023 // thus saving passwords from it works.
1024 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1025 FormsAddedBetweenParsingAndRendering) {
1026 NavigateToFile("/password/between_parsing_and_rendering.html");
1028 NavigationObserver observer(WebContents());
1029 scoped_ptr<PromptObserver> prompt_observer(
1030 PromptObserver::Create(WebContents()));
1031 std::string submit =
1032 "document.getElementById('username').value = 'temp';"
1033 "document.getElementById('password').value = 'random';"
1034 "document.getElementById('submit-button').click();";
1035 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1036 observer.Wait();
1038 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1041 // Test that if there was no previous page load then the PasswordManagerDriver
1042 // does not think that there were SSL errors on the current page. The test opens
1043 // a new tab with a URL for which the embedded test server issues a basic auth
1044 // challenge.
1045 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoLastLoadGoodLastLoad) {
1046 // Teach the embedded server to handle requests by issuing the basic auth
1047 // challenge.
1048 embedded_test_server()->RegisterRequestHandler(
1049 base::Bind(&HandleTestAuthRequest));
1051 LoginPromptBrowserTestObserver login_observer;
1052 // We need to register to all sources, because the navigation observer we are
1053 // interested in is for a new tab to be opened, and thus does not exist yet.
1054 login_observer.Register(content::NotificationService::AllSources());
1056 password_manager::TestPasswordStore* password_store =
1057 static_cast<password_manager::TestPasswordStore*>(
1058 PasswordStoreFactory::GetForProfile(browser()->profile(),
1059 Profile::IMPLICIT_ACCESS).get());
1060 EXPECT_TRUE(password_store->IsEmpty());
1062 // Navigate to a page requiring HTTP auth. Wait for the tab to get the correct
1063 // WebContents, but don't wait for navigation, which only finishes after
1064 // authentication.
1065 ui_test_utils::NavigateToURLWithDisposition(
1066 browser(),
1067 embedded_test_server()->GetURL("/basic_auth"),
1068 NEW_FOREGROUND_TAB,
1069 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
1071 content::NavigationController* nav_controller =
1072 &WebContents()->GetController();
1073 NavigationObserver nav_observer(WebContents());
1074 scoped_ptr<PromptObserver> prompt_observer(
1075 PromptObserver::Create(WebContents()));
1076 WindowedAuthNeededObserver auth_needed_observer(nav_controller);
1077 auth_needed_observer.Wait();
1079 WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
1080 // Offer valid credentials on the auth challenge.
1081 ASSERT_EQ(1u, login_observer.handlers().size());
1082 LoginHandler* handler = *login_observer.handlers().begin();
1083 ASSERT_TRUE(handler);
1084 // Any username/password will work.
1085 handler->SetAuth(base::UTF8ToUTF16("user"), base::UTF8ToUTF16("pwd"));
1086 auth_supplied_observer.Wait();
1088 // The password manager should be working correctly.
1089 nav_observer.Wait();
1090 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1091 prompt_observer->Accept();
1093 // Spin the message loop to make sure the password store had a chance to save
1094 // the password.
1095 base::RunLoop run_loop;
1096 run_loop.RunUntilIdle();
1097 EXPECT_FALSE(password_store->IsEmpty());
1100 // In some situations, multiple PasswordFormManager instances from
1101 // PasswordManager::pending_login_managers_ would match (via DoesManage) a form
1102 // to be provisionally saved. One of them might be a complete match, the other
1103 // all-but-action match. Normally, the former should be preferred, but if the
1104 // former has not finished matching, and the latter has, the latter should be
1105 // used (otherwise we'd give up even though we could have saved the password).
1106 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1107 PreferPasswordFormManagerWhichFinishedMatching) {
1108 NavigateToFile("/password/create_form_copy_on_submit.html");
1110 NavigationObserver observer(WebContents());
1111 scoped_ptr<PromptObserver> prompt_observer(
1112 PromptObserver::Create(WebContents()));
1113 std::string submit =
1114 "document.getElementById('username').value = 'overwrite_me';"
1115 "document.getElementById('password').value = 'random';"
1116 "document.getElementById('non-form-button').click();";
1117 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1118 observer.Wait();
1120 EXPECT_TRUE(prompt_observer->IsShowingPrompt());