Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_manager_browsertest.cc
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.
4
5 #include <string>
6
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"
50
51
52 // NavigationObserver ---------------------------------------------------------
53
54 namespace {
55
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) {}
63
64   virtual ~NavigationObserver() {}
65
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;
71   }
72
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();
81     }
82   }
83
84   void Wait() { message_loop_runner_->Run(); }
85
86  private:
87   std::string wait_for_path_;
88   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
89
90   DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
91 };
92
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() {}
99
100   // Checks if the prompt is being currently shown.
101   virtual bool IsShowingPrompt() const = 0;
102
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();
108   }
109
110   // Chooses the right implementation of PromptObserver and creates an instance
111   // of it.
112   static scoped_ptr<PromptObserver> Create(content::WebContents* web_contents);
113
114  protected:
115   PromptObserver() {}
116
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;
121
122  private:
123   DISALLOW_COPY_AND_ASSIGN(PromptObserver);
124 };
125
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);
133   }
134
135   virtual ~InfoBarObserver() {
136     if (infobar_service_)
137       infobar_service_->RemoveObserver(this);
138   }
139
140  private:
141   // PromptObserver:
142   virtual bool IsShowingPrompt() const OVERRIDE {
143     return infobar_is_being_shown_;
144   }
145
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.
150
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());
159   }
160
161   // infobars::InfoBarManager::Observer:
162   virtual void OnInfoBarAdded(infobars::InfoBar* infobar) OVERRIDE {
163     infobar_is_being_shown_ = true;
164   }
165
166   virtual void OnInfoBarRemoved(infobars::InfoBar* infobar,
167                                 bool animate) OVERRIDE {
168     infobar_is_being_shown_ = false;
169   }
170
171   virtual void OnManagerShuttingDown(
172       infobars::InfoBarManager* manager) OVERRIDE {
173     ASSERT_EQ(infobar_service_, manager);
174     infobar_service_->RemoveObserver(this);
175     infobar_service_ = NULL;
176   }
177
178   bool infobar_is_being_shown_;
179   InfoBarService* infobar_service_;
180
181   DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
182 };
183
184 class BubbleObserver : public PromptObserver {
185  public:
186   explicit BubbleObserver(content::WebContents* web_contents)
187       : ui_controller_(
188             ManagePasswordsUIController::FromWebContents(web_contents)) {}
189
190   virtual ~BubbleObserver() {}
191
192  private:
193   // PromptObserver:
194   virtual bool IsShowingPrompt() const OVERRIDE {
195     return ui_controller_->PasswordPendingUserDecision();
196   }
197
198   virtual void AcceptImpl() const OVERRIDE {
199     ui_controller_->SavePassword();
200     EXPECT_FALSE(IsShowingPrompt());
201   }
202
203   ManagePasswordsUIController* const ui_controller_;
204
205   DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
206 };
207
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));
215   }
216 }
217
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>();
225
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>();
239   }
240 }
241
242 }  // namespace
243
244
245 // PasswordManagerBrowserTest -------------------------------------------------
246
247 class PasswordManagerBrowserTest : public InProcessBrowserTest {
248  public:
249   PasswordManagerBrowserTest() {}
250   virtual ~PasswordManagerBrowserTest() {}
251
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));
264   }
265
266   virtual void TearDownOnMainThread() OVERRIDE {
267     ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
268   }
269
270  protected:
271   content::WebContents* WebContents() {
272     return browser()->tab_strip_model()->GetActiveWebContents();
273   }
274
275   content::RenderViewHost* RenderViewHost() {
276     return WebContents()->GetRenderViewHost();
277   }
278
279   // Wrapper around ui_test_utils::NavigateToURL that waits until
280   // DidFinishLoad() fires. Normally this function returns after
281   // DidStopLoading(), which caused flakiness as the NavigationObserver
282   // would sometimes see the DidFinishLoad event from a previous navigation and
283   // return immediately.
284   void NavigateToFile(const std::string& path) {
285     NavigationObserver observer(WebContents());
286     GURL url = embedded_test_server()->GetURL(path);
287     ui_test_utils::NavigateToURL(browser(), url);
288     observer.Wait();
289   }
290
291   // Waits until the "value" attribute of the HTML element with |element_id| is
292   // equal to |expected_value|. If the current value is not as expected, this
293   // waits until the "change" event is fired for the element. This also
294   // guarantees that once the real value matches the expected, the JavaScript
295   // event loop is spun to allow all other possible events to take place.
296   void WaitForElementValue(const std::string& element_id,
297                            const std::string& expected_value);
298   // Checks that the current "value" attribute of the HTML element with
299   // |element_id| is equal to |expected_value|.
300   void CheckElementValue(const std::string& element_id,
301                          const std::string& expected_value);
302
303  private:
304   DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
305 };
306
307 void PasswordManagerBrowserTest::WaitForElementValue(
308     const std::string& element_id,
309     const std::string& expected_value) {
310   enum ReturnCodes {  // Possible results of the JavaScript code.
311     RETURN_CODE_OK,
312     RETURN_CODE_NO_ELEMENT,
313     RETURN_CODE_WRONG_VALUE,
314     RETURN_CODE_INVALID,
315   };
316   const std::string value_check_function = base::StringPrintf(
317       "function valueCheck() {"
318       "  var element = document.getElementById('%s');"
319       "  return element && element.value == '%s';"
320       "}",
321       element_id.c_str(),
322       expected_value.c_str());
323   const std::string script =
324       value_check_function +
325       base::StringPrintf(
326           "if (valueCheck()) {"
327           "  /* Spin the event loop with setTimeout. */"
328           "  setTimeout(window.domAutomationController.send(%d), 0);"
329           "} else {"
330           "  var element = document.getElementById('%s');"
331           "  if (!element)"
332           "    window.domAutomationController.send(%d);"
333           "  element.onchange = function() {"
334           "    if (valueCheck()) {"
335           "      /* Spin the event loop with setTimeout. */"
336           "      setTimeout(window.domAutomationController.send(%d), 0);"
337           "    } else {"
338           "      window.domAutomationController.send(%d);"
339           "    }"
340           "  };"
341           "}",
342           RETURN_CODE_OK,
343           element_id.c_str(),
344           RETURN_CODE_NO_ELEMENT,
345           RETURN_CODE_OK,
346           RETURN_CODE_WRONG_VALUE);
347   int return_value = RETURN_CODE_INVALID;
348   ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
349       RenderViewHost(), script, &return_value));
350   EXPECT_EQ(RETURN_CODE_OK, return_value)
351       << "element_id = " << element_id
352       << ", expected_value = " << expected_value;
353 }
354
355 void PasswordManagerBrowserTest::CheckElementValue(
356     const std::string& element_id,
357     const std::string& expected_value) {
358   const std::string value_check_script = base::StringPrintf(
359       "var element = document.getElementById('%s');"
360       "window.domAutomationController.send(element && element.value == '%s');",
361       element_id.c_str(),
362       expected_value.c_str());
363   bool return_value = false;
364   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
365       RenderViewHost(), value_check_script, &return_value));
366   EXPECT_TRUE(return_value) << "element_id = " << element_id
367                             << ", expected_value = " << expected_value;
368 }
369
370 // Actual tests ---------------------------------------------------------------
371 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
372                        PromptForNormalSubmit) {
373   NavigateToFile("/password/password_form.html");
374
375   // Fill a form and submit through a <input type="submit"> button. Nothing
376   // special.
377   NavigationObserver observer(WebContents());
378   scoped_ptr<PromptObserver> prompt_observer(
379       PromptObserver::Create(WebContents()));
380   std::string fill_and_submit =
381       "document.getElementById('username_field').value = 'temp';"
382       "document.getElementById('password_field').value = 'random';"
383       "document.getElementById('input_submit_button').click()";
384   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
385   observer.Wait();
386   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
387 }
388
389 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
390                        PromptForSubmitWithInPageNavigation) {
391   NavigateToFile("/password/password_navigate_before_submit.html");
392
393   // Fill a form and submit through a <input type="submit"> button. Nothing
394   // special. The form does an in-page navigation before submitting.
395   NavigationObserver observer(WebContents());
396   scoped_ptr<PromptObserver> prompt_observer(
397       PromptObserver::Create(WebContents()));
398   std::string fill_and_submit =
399       "document.getElementById('username_field').value = 'temp';"
400       "document.getElementById('password_field').value = 'random';"
401       "document.getElementById('input_submit_button').click()";
402   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
403   observer.Wait();
404   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
405 }
406
407 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
408                        LoginSuccessWithUnrelatedForm) {
409   // Log in, see a form on the landing page. That form is not related to the
410   // login form (=has a different action), so we should offer saving the
411   // password.
412   NavigateToFile("/password/password_form.html");
413
414   NavigationObserver observer(WebContents());
415   scoped_ptr<PromptObserver> prompt_observer(
416       PromptObserver::Create(WebContents()));
417   std::string fill_and_submit =
418       "document.getElementById('username_unrelated').value = 'temp';"
419       "document.getElementById('password_unrelated').value = 'random';"
420       "document.getElementById('submit_unrelated').click()";
421   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
422   observer.Wait();
423   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
424 }
425
426 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, LoginFailed) {
427   // Log in, see a form on the landing page. That form is not related to the
428   // login form (=has a different action), so we should offer saving the
429   // password.
430   NavigateToFile("/password/password_form.html");
431
432   NavigationObserver observer(WebContents());
433   scoped_ptr<PromptObserver> prompt_observer(
434       PromptObserver::Create(WebContents()));
435   std::string fill_and_submit =
436       "document.getElementById('username_failed').value = 'temp';"
437       "document.getElementById('password_failed').value = 'random';"
438       "document.getElementById('submit_failed').click()";
439   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
440   observer.Wait();
441   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
442 }
443
444 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
445   NavigateToFile("/password/password_form.html");
446
447   // Fill a form and submit through a <input type="submit"> button. The form
448   // points to a redirection page.
449   NavigationObserver observer(WebContents());
450   scoped_ptr<PromptObserver> prompt_observer(
451       PromptObserver::Create(WebContents()));
452   std::string fill_and_submit =
453       "document.getElementById('username_redirect').value = 'temp';"
454       "document.getElementById('password_redirect').value = 'random';"
455       "document.getElementById('submit_redirect').click()";
456   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
457   observer.Wait();
458   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
459
460   // The redirection page now redirects via Javascript. We check that the
461   // infobar stays.
462   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
463                                      "window.location.href = 'done.html';"));
464   observer.Wait();
465   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
466 }
467
468 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
469                        PromptForSubmitUsingJavaScript) {
470   NavigateToFile("/password/password_form.html");
471
472   // Fill a form and submit using <button> that calls submit() on the form.
473   // This should work regardless of the type of element, as long as submit() is
474   // called.
475   NavigationObserver observer(WebContents());
476   scoped_ptr<PromptObserver> prompt_observer(
477       PromptObserver::Create(WebContents()));
478   std::string fill_and_submit =
479       "document.getElementById('username_field').value = 'temp';"
480       "document.getElementById('password_field').value = 'random';"
481       "document.getElementById('submit_button').click()";
482   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
483   observer.Wait();
484   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
485 }
486
487 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
488 // platforms.
489 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
490                        DISABLED_PromptForDynamicForm) {
491   NavigateToFile("/password/dynamic_password_form.html");
492
493   // Fill the dynamic password form and submit.
494   NavigationObserver observer(WebContents());
495   scoped_ptr<PromptObserver> prompt_observer(
496       PromptObserver::Create(WebContents()));
497   std::string fill_and_submit =
498       "document.getElementById('create_form_button').click();"
499       "window.setTimeout(function() {"
500       "  document.dynamic_form.username.value = 'tempro';"
501       "  document.dynamic_form.password.value = 'random';"
502       "  document.dynamic_form.submit();"
503       "}, 0)";
504   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
505   observer.Wait();
506   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
507 }
508
509 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
510   NavigateToFile("/password/password_form.html");
511
512   // Don't fill the password form, just navigate away. Shouldn't prompt.
513   NavigationObserver observer(WebContents());
514   scoped_ptr<PromptObserver> prompt_observer(
515       PromptObserver::Create(WebContents()));
516   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
517                                      "window.location.href = 'done.html';"));
518   observer.Wait();
519   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
520 }
521
522 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
523                        NoPromptForSubFrameNavigation) {
524   NavigateToFile("/password/multi_frames.html");
525
526   // If you are filling out a password form in one frame and a different frame
527   // navigates, this should not trigger the infobar.
528   NavigationObserver observer(WebContents());
529   scoped_ptr<PromptObserver> prompt_observer(
530       PromptObserver::Create(WebContents()));
531   observer.SetPathToWaitFor("/password/done.html");
532   std::string fill =
533       "var first_frame = document.getElementById('first_frame');"
534       "var frame_doc = first_frame.contentDocument;"
535       "frame_doc.getElementById('username_field').value = 'temp';"
536       "frame_doc.getElementById('password_field').value = 'random';";
537   std::string navigate_frame =
538       "var second_iframe = document.getElementById('second_frame');"
539       "second_iframe.contentWindow.location.href = 'done.html';";
540
541   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
542   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
543   observer.Wait();
544   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
545 }
546
547 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
548                        PromptAfterSubmitWithSubFrameNavigation) {
549   NavigateToFile("/password/multi_frames.html");
550
551   // Make sure that we prompt to save password even if a sub-frame navigation
552   // happens first.
553   NavigationObserver observer(WebContents());
554   scoped_ptr<PromptObserver> prompt_observer(
555       PromptObserver::Create(WebContents()));
556   observer.SetPathToWaitFor("/password/done.html");
557   std::string navigate_frame =
558       "var second_iframe = document.getElementById('second_frame');"
559       "second_iframe.contentWindow.location.href = 'other.html';";
560   std::string fill_and_submit =
561       "var first_frame = document.getElementById('first_frame');"
562       "var frame_doc = first_frame.contentDocument;"
563       "frame_doc.getElementById('username_field').value = 'temp';"
564       "frame_doc.getElementById('password_field').value = 'random';"
565       "frame_doc.getElementById('input_submit_button').click();";
566
567   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
568   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
569   observer.Wait();
570   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
571 }
572
573 IN_PROC_BROWSER_TEST_F(
574     PasswordManagerBrowserTest,
575     NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage) {
576   NavigateToFile("/password/multi_frames.html");
577
578   // Make sure that we don't prompt to save the password for a failed login
579   // from the main frame with multiple frames in the same page.
580   NavigationObserver observer(WebContents());
581   scoped_ptr<PromptObserver> prompt_observer(
582       PromptObserver::Create(WebContents()));
583   std::string fill_and_submit =
584       "document.getElementById('username_failed').value = 'temp';"
585       "document.getElementById('password_failed').value = 'random';"
586       "document.getElementById('submit_failed').click();";
587
588   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
589   observer.Wait();
590   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
591 }
592
593 IN_PROC_BROWSER_TEST_F(
594     PasswordManagerBrowserTest,
595     NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage) {
596   NavigateToFile("/password/multi_frames.html");
597
598   // Make sure that we don't prompt to save the password for a failed login
599   // from a sub-frame with multiple frames in the same page.
600   NavigationObserver observer(WebContents());
601   scoped_ptr<PromptObserver> prompt_observer(
602       PromptObserver::Create(WebContents()));
603   std::string fill_and_submit =
604       "var first_frame = document.getElementById('first_frame');"
605       "var frame_doc = first_frame.contentDocument;"
606       "frame_doc.getElementById('username_failed').value = 'temp';"
607       "frame_doc.getElementById('password_failed').value = 'random';"
608       "frame_doc.getElementById('submit_failed').click();"
609       "window.parent.location.href = 'multi_frames.html';";
610
611   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
612   observer.Wait();
613   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
614 }
615
616 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
617 #if defined(OS_WIN) && defined(USE_ASH)
618   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
619   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
620     return;
621 #endif
622   NavigateToFile("/password/password_xhr_submit.html");
623
624   // Verify that we show the save password prompt if a form returns false
625   // in its onsubmit handler but instead logs in/navigates via XHR.
626   // Note that calling 'submit()' on a form with javascript doesn't call
627   // the onsubmit handler, so we click the submit button instead.
628   NavigationObserver observer(WebContents());
629   scoped_ptr<PromptObserver> prompt_observer(
630       PromptObserver::Create(WebContents()));
631   std::string fill_and_submit =
632       "document.getElementById('username_field').value = 'temp';"
633       "document.getElementById('password_field').value = 'random';"
634       "document.getElementById('submit_button').click()";
635   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
636   observer.Wait();
637   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
638 }
639
640 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
641                        PromptForXHRWithoutOnSubmit) {
642   NavigateToFile("/password/password_xhr_submit.html");
643
644   // Verify that if XHR navigation occurs and the form is properly filled out,
645   // we try and save the password even though onsubmit hasn't been called.
646   NavigationObserver observer(WebContents());
647   scoped_ptr<PromptObserver> prompt_observer(
648       PromptObserver::Create(WebContents()));
649   std::string fill_and_navigate =
650       "document.getElementById('username_field').value = 'temp';"
651       "document.getElementById('password_field').value = 'random';"
652       "send_xhr()";
653   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
654   observer.Wait();
655   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
656 }
657
658 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfLinkClicked) {
659   NavigateToFile("/password/password_form.html");
660
661   // Verify that if the user takes a direct action to leave the page, we don't
662   // prompt to save the password even if the form is already filled out.
663   NavigationObserver observer(WebContents());
664   scoped_ptr<PromptObserver> prompt_observer(
665       PromptObserver::Create(WebContents()));
666   std::string fill_and_click_link =
667       "document.getElementById('username_field').value = 'temp';"
668       "document.getElementById('password_field').value = 'random';"
669       "document.getElementById('link').click();";
670   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link));
671   observer.Wait();
672   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
673 }
674
675 // TODO(jam): http://crbug.com/350550
676 #if !defined(OS_WIN)
677 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
678                        VerifyPasswordGenerationUpload) {
679   // Prevent Autofill requests from actually going over the wire.
680   net::TestURLFetcherFactory factory;
681   // Disable Autofill requesting access to AddressBook data. This causes
682   // the test to hang on Mac.
683   autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
684
685   // Visit a signup form.
686   NavigateToFile("/password/signup_form.html");
687
688   // Enter a password and save it.
689   NavigationObserver first_observer(WebContents());
690   scoped_ptr<PromptObserver> prompt_observer(
691       PromptObserver::Create(WebContents()));
692   std::string fill_and_submit =
693       "document.getElementById('other_info').value = 'stuff';"
694       "document.getElementById('username_field').value = 'my_username';"
695       "document.getElementById('password_field').value = 'password';"
696       "document.getElementById('input_submit_button').click()";
697   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
698
699   first_observer.Wait();
700   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
701   prompt_observer->Accept();
702
703   // Now navigate to a login form that has similar HTML markup.
704   NavigateToFile("/password/password_form.html");
705
706   // Simulate a user click to force an autofill of the form's DOM value, not
707   // just the suggested value.
708   content::SimulateMouseClick(
709       WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
710
711   // The form should be filled with the previously submitted username.
712   std::string get_username =
713       "window.domAutomationController.send("
714       "document.getElementById('username_field').value);";
715   std::string actual_username;
716   ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
717                                                      get_username,
718                                                      &actual_username));
719   ASSERT_EQ("my_username", actual_username);
720
721   // Submit the form and verify that there is no infobar (as the password
722   // has already been saved).
723   NavigationObserver second_observer(WebContents());
724   scoped_ptr<PromptObserver> second_prompt_observer(
725       PromptObserver::Create(WebContents()));
726   std::string submit_form =
727       "document.getElementById('input_submit_button').click()";
728   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form));
729   second_observer.Wait();
730   EXPECT_FALSE(second_prompt_observer->IsShowingPrompt());
731
732   // Verify that we sent two pings to Autofill. One vote for of PASSWORD for
733   // the current form, and one vote for ACCOUNT_CREATION_PASSWORD on the
734   // original form since it has more than 2 text input fields and was used for
735   // 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(2, snapshot->GetCount(1 /* success */));
744 }
745 #endif
746
747 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
748   NavigateToFile("/password/password_submit_from_iframe.html");
749
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()";
762
763   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
764   observer.Wait();
765   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
766 }
767
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");
773
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());
784 }
785
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");
791
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());
802 }
803
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");
809
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());
823 }
824
825 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
826   NavigateToFile("/password/multi_frames.html");
827
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';";
844
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.
849 }
850
851 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PasswordValueAccessible) {
852   NavigateToFile("/password/form_and_link.html");
853
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);
861
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();
874
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();
879
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");
892 }
893
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");
902
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();
915
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();
920
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;
928 }
929 #endif
930
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");
935
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());
944 }
945
946 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
947                        PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
948   NavigateToFile("/password/password_form.html");
949
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());
961 }
962
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());
969
970   EXPECT_TRUE(password_store->IsEmpty());
971
972   NavigateToFile("/password/password_form.html");
973
974   // Add the enable-automatic-password-saving switch.
975   CommandLine::ForCurrentProcess()->AppendSwitch(
976       password_manager::switches::kEnableAutomaticPasswordSaving);
977
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());
998   }
999 }
1000
1001 // Test fix for crbug.com/368690.
1002 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
1003   NavigateToFile("/password/password_form.html");
1004
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));
1009
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());
1019 }
1020
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");
1027
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();
1037
1038   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1039 }
1040
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));
1050
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());
1055
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());
1061
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);
1070
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();
1078
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();
1087
1088   // The password manager should be working correctly.
1089   nav_observer.Wait();
1090   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1091   prompt_observer->Accept();
1092
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());
1098 }
1099
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");
1109
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();
1119
1120   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1121 }
1122