1c3de2fa8bf49344a1fc93f312a721ab4a6dfd2e
[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 "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
12 #include "chrome/browser/infobars/infobar_service.h"
13 #include "chrome/browser/password_manager/password_store_factory.h"
14 #include "chrome/browser/password_manager/test_password_store_service.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/test_switches.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "components/autofill/core/browser/autofill_test_utils.h"
22 #include "components/infobars/core/infobar.h"
23 #include "components/infobars/core/infobar_manager.h"
24 #include "components/password_manager/core/browser/test_password_store.h"
25 #include "components/password_manager/core/common/password_manager_switches.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/test_utils.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/url_request/test_url_fetcher_factory.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "third_party/WebKit/public/web/WebInputEvent.h"
35 #include "ui/events/keycodes/keyboard_codes.h"
36
37
38 // NavigationObserver ---------------------------------------------------------
39
40 namespace {
41
42 // Observer that waits for navigation to complete and for the password infobar
43 // to be shown.
44 class NavigationObserver : public content::WebContentsObserver,
45                            public infobars::InfoBarManager::Observer {
46  public:
47   explicit NavigationObserver(content::WebContents* web_contents)
48       : content::WebContentsObserver(web_contents),
49         message_loop_runner_(new content::MessageLoopRunner),
50         infobar_shown_(false),
51         infobar_removed_(false),
52         should_automatically_accept_infobar_(true),
53         infobar_service_(InfoBarService::FromWebContents(web_contents)) {
54     infobar_service_->AddObserver(this);
55   }
56
57   virtual ~NavigationObserver() {
58     if (infobar_service_)
59       infobar_service_->RemoveObserver(this);
60   }
61
62   // Normally Wait() will not return until a main frame navigation occurs.
63   // If a path is set, Wait() will return after this path has been seen,
64   // regardless of the frame that navigated. Useful for multi-frame pages.
65   void SetPathToWaitFor(const std::string& path) {
66     wait_for_path_ = path;
67   }
68
69   // content::WebContentsObserver:
70   virtual void DidFinishLoad(
71       int64 frame_id,
72       const GURL& validated_url,
73       bool is_main_frame,
74       content::RenderViewHost* render_view_host) OVERRIDE {
75     if (!wait_for_path_.empty()) {
76       if (validated_url.path() == wait_for_path_)
77         message_loop_runner_->Quit();
78     } else if (is_main_frame) {
79       message_loop_runner_->Quit();
80     }
81   }
82
83   bool infobar_shown() const { return infobar_shown_; }
84   bool infobar_removed() const { return infobar_removed_; }
85
86   void disable_should_automatically_accept_infobar() {
87     should_automatically_accept_infobar_ = false;
88   }
89
90   void Wait() {
91     message_loop_runner_->Run();
92   }
93
94  private:
95   // infobars::InfoBarManager::Observer:
96   virtual void OnInfoBarAdded(infobars::InfoBar* infobar) OVERRIDE {
97     if (should_automatically_accept_infobar_) {
98       infobar_service_->infobar_at(0)->delegate()->
99           AsConfirmInfoBarDelegate()->Accept();
100     }
101     infobar_shown_ = true;
102   }
103
104   virtual void OnInfoBarRemoved(infobars::InfoBar* infobar,
105                                 bool animate) OVERRIDE {
106     infobar_removed_ = true;
107   }
108
109   virtual void OnManagerShuttingDown(
110       infobars::InfoBarManager* manager) OVERRIDE {
111     ASSERT_EQ(infobar_service_, manager);
112     infobar_service_->RemoveObserver(this);
113     infobar_service_ = NULL;
114   }
115
116   std::string wait_for_path_;
117   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
118   bool infobar_shown_;
119   bool infobar_removed_;
120   // If |should_automatically_accept_infobar_| is true, then whenever the test
121   // sees an infobar added, it will click its accepting button. Default = true.
122   bool should_automatically_accept_infobar_;
123   InfoBarService* infobar_service_;
124
125   DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
126 };
127
128 }  // namespace
129
130
131 // PasswordManagerBrowserTest -------------------------------------------------
132
133 class PasswordManagerBrowserTest : public InProcessBrowserTest {
134  public:
135   PasswordManagerBrowserTest() {}
136   virtual ~PasswordManagerBrowserTest() {}
137
138   // InProcessBrowserTest:
139   virtual void SetUpOnMainThread() OVERRIDE {
140     // Use TestPasswordStore to remove a possible race. Normally the
141     // PasswordStore does its database manipulation on the DB thread, which
142     // creates a possible race during navigation. Specifically the
143     // PasswordManager will ignore any forms in a page if the load from the
144     // PasswordStore has not completed.
145     PasswordStoreFactory::GetInstance()->SetTestingFactory(
146         browser()->profile(), TestPasswordStoreService::Build);
147   }
148
149  protected:
150   content::WebContents* WebContents() {
151     return browser()->tab_strip_model()->GetActiveWebContents();
152   }
153
154   content::RenderViewHost* RenderViewHost() {
155     return WebContents()->GetRenderViewHost();
156   }
157
158   // Wrapper around ui_test_utils::NavigateToURL that waits until
159   // DidFinishLoad() fires. Normally this function returns after
160   // DidStopLoading(), which caused flakiness as the NavigationObserver
161   // would sometimes see the DidFinishLoad event from a previous navigation and
162   // return immediately.
163   void NavigateToFile(const std::string& path) {
164     if (!embedded_test_server()->Started())
165       ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
166
167     ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
168         password_manager::switches::kEnableAutomaticPasswordSaving));
169     NavigationObserver observer(WebContents());
170     GURL url = embedded_test_server()->GetURL(path);
171     ui_test_utils::NavigateToURL(browser(), url);
172     observer.Wait();
173   }
174
175   // Executes |script| and uses the EXPECT macros to check the return value
176   // against |expected_return_value|.
177   void CheckScriptReturnValue(std::string& script, bool expected_return_value);
178
179  private:
180   DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
181 };
182
183 void PasswordManagerBrowserTest::CheckScriptReturnValue(
184     std::string& script,
185     bool expected_return_value) {
186   const std::string wrapped_script =
187       std::string("window.domAutomationController.send(") + script + ");";
188   bool return_value = !expected_return_value;
189   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
190       RenderViewHost(), wrapped_script, &return_value));
191   EXPECT_EQ(expected_return_value, return_value) << "script = " << script;
192 }
193
194 // Actual tests ---------------------------------------------------------------
195 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
196                        PromptForNormalSubmit) {
197   NavigateToFile("/password/password_form.html");
198
199   // Fill a form and submit through a <input type="submit"> button. Nothing
200   // special.
201   NavigationObserver observer(WebContents());
202   std::string fill_and_submit =
203       "document.getElementById('username_field').value = 'temp';"
204       "document.getElementById('password_field').value = 'random';"
205       "document.getElementById('input_submit_button').click()";
206   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
207   observer.Wait();
208   EXPECT_TRUE(observer.infobar_shown());
209 }
210
211 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
212                        PromptForSubmitWithInPageNavigation) {
213   NavigateToFile("/password/password_navigate_before_submit.html");
214
215   // Fill a form and submit through a <input type="submit"> button. Nothing
216   // special. The form does an in-page navigation before submitting.
217   NavigationObserver observer(WebContents());
218   std::string fill_and_submit =
219       "document.getElementById('username_field').value = 'temp';"
220       "document.getElementById('password_field').value = 'random';"
221       "document.getElementById('input_submit_button').click()";
222   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
223   observer.Wait();
224   EXPECT_TRUE(observer.infobar_shown());
225 }
226
227 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
228                        LoginSuccessWithUnrelatedForm) {
229   // Log in, see a form on the landing page. That form is not related to the
230   // login form (=has a different action), so we should offer saving the
231   // password.
232   NavigateToFile("/password/password_form.html");
233
234   NavigationObserver observer(WebContents());
235   std::string fill_and_submit =
236       "document.getElementById('username_unrelated').value = 'temp';"
237       "document.getElementById('password_unrelated').value = 'random';"
238       "document.getElementById('submit_unrelated').click()";
239   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
240   observer.Wait();
241   EXPECT_TRUE(observer.infobar_shown());
242 }
243
244 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, LoginFailed) {
245   // Log in, see a form on the landing page. That form is not related to the
246   // login form (=has a different action), so we should offer saving the
247   // password.
248   NavigateToFile("/password/password_form.html");
249
250   NavigationObserver observer(WebContents());
251   std::string fill_and_submit =
252       "document.getElementById('username_failed').value = 'temp';"
253       "document.getElementById('password_failed').value = 'random';"
254       "document.getElementById('submit_failed').click()";
255   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
256   observer.Wait();
257   EXPECT_FALSE(observer.infobar_shown());
258 }
259
260 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
261   NavigateToFile("/password/password_form.html");
262
263   // Fill a form and submit through a <input type="submit"> button. The form
264   // points to a redirection page.
265   NavigationObserver observer(WebContents());
266   std::string fill_and_submit =
267       "document.getElementById('username_redirect').value = 'temp';"
268       "document.getElementById('password_redirect').value = 'random';"
269       "document.getElementById('submit_redirect').click()";
270   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
271   observer.disable_should_automatically_accept_infobar();
272   observer.Wait();
273   EXPECT_TRUE(observer.infobar_shown());
274
275   // The redirection page now redirects via Javascript. We check that the
276   // infobar stays.
277   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
278                                      "window.location.href = 'done.html';"));
279   observer.Wait();
280   EXPECT_FALSE(observer.infobar_removed());
281 }
282
283 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
284                        PromptForSubmitUsingJavaScript) {
285   NavigateToFile("/password/password_form.html");
286
287   // Fill a form and submit using <button> that calls submit() on the form.
288   // This should work regardless of the type of element, as long as submit() is
289   // called.
290   NavigationObserver observer(WebContents());
291   std::string fill_and_submit =
292       "document.getElementById('username_field').value = 'temp';"
293       "document.getElementById('password_field').value = 'random';"
294       "document.getElementById('submit_button').click()";
295   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
296   observer.Wait();
297   EXPECT_TRUE(observer.infobar_shown());
298 }
299
300 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
301 // platforms.
302 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
303                        DISABLED_PromptForDynamicForm) {
304   NavigateToFile("/password/dynamic_password_form.html");
305
306   // Fill the dynamic password form and submit.
307   NavigationObserver observer(WebContents());
308   std::string fill_and_submit =
309       "document.getElementById('create_form_button').click();"
310       "window.setTimeout(function() {"
311       "  document.dynamic_form.username.value = 'tempro';"
312       "  document.dynamic_form.password.value = 'random';"
313       "  document.dynamic_form.submit();"
314       "}, 0)";
315   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
316   observer.Wait();
317   EXPECT_TRUE(observer.infobar_shown());
318 }
319
320 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
321   NavigateToFile("/password/password_form.html");
322
323   // Don't fill the password form, just navigate away. Shouldn't prompt.
324   NavigationObserver observer(WebContents());
325   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
326                                      "window.location.href = 'done.html';"));
327   observer.Wait();
328   EXPECT_FALSE(observer.infobar_shown());
329 }
330
331 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
332                        NoPromptForSubFrameNavigation) {
333   NavigateToFile("/password/multi_frames.html");
334
335   // If you are filling out a password form in one frame and a different frame
336   // navigates, this should not trigger the infobar.
337   NavigationObserver observer(WebContents());
338   observer.SetPathToWaitFor("/password/done.html");
339   std::string fill =
340       "var first_frame = document.getElementById('first_frame');"
341       "var frame_doc = first_frame.contentDocument;"
342       "frame_doc.getElementById('username_field').value = 'temp';"
343       "frame_doc.getElementById('password_field').value = 'random';";
344   std::string navigate_frame =
345       "var second_iframe = document.getElementById('second_frame');"
346       "second_iframe.contentWindow.location.href = 'done.html';";
347
348   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
349   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
350   observer.Wait();
351   EXPECT_FALSE(observer.infobar_shown());
352 }
353
354 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
355                        PromptAfterSubmitWithSubFrameNavigation) {
356   NavigateToFile("/password/multi_frames.html");
357
358   // Make sure that we prompt to save password even if a sub-frame navigation
359   // happens first.
360   NavigationObserver observer(WebContents());
361   observer.SetPathToWaitFor("/password/done.html");
362   std::string navigate_frame =
363       "var second_iframe = document.getElementById('second_frame');"
364       "second_iframe.contentWindow.location.href = 'other.html';";
365   std::string fill_and_submit =
366       "var first_frame = document.getElementById('first_frame');"
367       "var frame_doc = first_frame.contentDocument;"
368       "frame_doc.getElementById('username_field').value = 'temp';"
369       "frame_doc.getElementById('password_field').value = 'random';"
370       "frame_doc.getElementById('input_submit_button').click();";
371
372   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
373   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
374   observer.Wait();
375   EXPECT_TRUE(observer.infobar_shown());
376 }
377
378 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
379                        PromptForXHRSubmit) {
380 #if defined(OS_WIN) && defined(USE_ASH)
381   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
382   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
383     return;
384 #endif
385   NavigateToFile("/password/password_xhr_submit.html");
386
387   // Verify that we show the save password prompt if a form returns false
388   // in its onsubmit handler but instead logs in/navigates via XHR.
389   // Note that calling 'submit()' on a form with javascript doesn't call
390   // the onsubmit handler, so we click the submit button instead.
391   NavigationObserver observer(WebContents());
392   std::string fill_and_submit =
393       "document.getElementById('username_field').value = 'temp';"
394       "document.getElementById('password_field').value = 'random';"
395       "document.getElementById('submit_button').click()";
396   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
397   observer.Wait();
398   EXPECT_TRUE(observer.infobar_shown());
399 }
400
401 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
402                        PromptForXHRWithoutOnSubmit) {
403   NavigateToFile("/password/password_xhr_submit.html");
404
405   // Verify that if XHR navigation occurs and the form is properly filled out,
406   // we try and save the password even though onsubmit hasn't been called.
407   NavigationObserver observer(WebContents());
408   std::string fill_and_navigate =
409       "document.getElementById('username_field').value = 'temp';"
410       "document.getElementById('password_field').value = 'random';"
411       "send_xhr()";
412   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
413   observer.Wait();
414   EXPECT_TRUE(observer.infobar_shown());
415 }
416
417 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
418                        NoPromptIfLinkClicked) {
419   NavigateToFile("/password/password_form.html");
420
421   // Verify that if the user takes a direct action to leave the page, we don't
422   // prompt to save the password even if the form is already filled out.
423   NavigationObserver observer(WebContents());
424   std::string fill_and_click_link =
425       "document.getElementById('username_field').value = 'temp';"
426       "document.getElementById('password_field').value = 'random';"
427       "document.getElementById('link').click();";
428   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link));
429   observer.Wait();
430   EXPECT_FALSE(observer.infobar_shown());
431 }
432
433 // TODO(jam): http://crbug.com/350550
434 #if !defined(OS_WIN)
435 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
436                        VerifyPasswordGenerationUpload) {
437   // Prevent Autofill requests from actually going over the wire.
438   net::TestURLFetcherFactory factory;
439   // Disable Autofill requesting access to AddressBook data. This causes
440   // the test to hang on Mac.
441   autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
442
443   // Visit a signup form.
444   NavigateToFile("/password/signup_form.html");
445
446   // Enter a password and save it.
447   NavigationObserver first_observer(WebContents());
448   std::string fill_and_submit =
449       "document.getElementById('other_info').value = 'stuff';"
450       "document.getElementById('username_field').value = 'my_username';"
451       "document.getElementById('password_field').value = 'password';"
452       "document.getElementById('input_submit_button').click()";
453   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
454
455   first_observer.Wait();
456   ASSERT_TRUE(first_observer.infobar_shown());
457
458   // Now navigate to a login form that has similar HTML markup.
459   NavigateToFile("/password/password_form.html");
460
461   // Simulate a user click to force an autofill of the form's DOM value, not
462   // just the suggested value.
463   content::SimulateMouseClick(
464       WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
465
466   // The form should be filled with the previously submitted username.
467   std::string get_username =
468       "window.domAutomationController.send("
469       "document.getElementById('username_field').value);";
470   std::string actual_username;
471   ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
472                                                      get_username,
473                                                      &actual_username));
474   ASSERT_EQ("my_username", actual_username);
475
476   // Submit the form and verify that there is no infobar (as the password
477   // has already been saved).
478   NavigationObserver second_observer(WebContents());
479   std::string submit_form =
480       "document.getElementById('input_submit_button').click()";
481   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form));
482   second_observer.Wait();
483   EXPECT_FALSE(second_observer.infobar_shown());
484
485   // Verify that we sent a ping to Autofill saying that the original form
486   // was likely an account creation form since it has more than 2 text input
487   // fields and was used for the first time on a different form.
488   base::HistogramBase* upload_histogram =
489       base::StatisticsRecorder::FindHistogram(
490           "PasswordGeneration.UploadStarted");
491   ASSERT_TRUE(upload_histogram);
492   scoped_ptr<base::HistogramSamples> snapshot =
493       upload_histogram->SnapshotSamples();
494   EXPECT_EQ(0, snapshot->GetCount(0 /* failure */));
495   EXPECT_EQ(1, snapshot->GetCount(1 /* success */));
496 }
497 #endif
498
499 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
500   NavigateToFile("/password/password_submit_from_iframe.html");
501
502   // Submit a form in an iframe, then cause the whole page to navigate without a
503   // user gesture. We expect the save password prompt to be shown here, because
504   // some pages use such iframes for login forms.
505   NavigationObserver observer(WebContents());
506   std::string fill_and_submit =
507       "var iframe = document.getElementById('test_iframe');"
508       "var iframe_doc = iframe.contentDocument;"
509       "iframe_doc.getElementById('username_field').value = 'temp';"
510       "iframe_doc.getElementById('password_field').value = 'random';"
511       "iframe_doc.getElementById('submit_button').click()";
512
513   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
514   observer.Wait();
515   EXPECT_TRUE(observer.infobar_shown());
516 }
517
518 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
519                        PromptForInputElementWithoutName) {
520   // Check that the prompt is shown for forms where input elements lack the
521   // "name" attribute but the "id" is present.
522   NavigateToFile("/password/password_form.html");
523
524   NavigationObserver observer(WebContents());
525   std::string fill_and_submit =
526       "document.getElementById('username_field_no_name').value = 'temp';"
527       "document.getElementById('password_field_no_name').value = 'random';"
528       "document.getElementById('input_submit_button_no_name').click()";
529   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
530   observer.Wait();
531   EXPECT_TRUE(observer.infobar_shown());
532 }
533
534 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
535                        PromptForInputElementWithoutId) {
536   // Check that the prompt is shown for forms where input elements lack the
537   // "id" attribute but the "name" attribute is present.
538   NavigateToFile("/password/password_form.html");
539
540   NavigationObserver observer(WebContents());
541   std::string fill_and_submit =
542       "document.getElementsByName('username_field_no_id')[0].value = 'temp';"
543       "document.getElementsByName('password_field_no_id')[0].value = 'random';"
544       "document.getElementsByName('input_submit_button_no_id')[0].click()";
545   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
546   observer.Wait();
547   EXPECT_TRUE(observer.infobar_shown());
548 }
549
550 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
551                        NoPromptForInputElementWithoutIdAndName) {
552   // Check that no prompt is shown for forms where the input fields lack both
553   // the "id" and the "name" attributes.
554   NavigateToFile("/password/password_form.html");
555
556   NavigationObserver observer(WebContents());
557   std::string fill_and_submit =
558       "var form = document.getElementById('testform_elements_no_id_no_name');"
559       "var username = form.children[0];"
560       "username.value = 'temp';"
561       "var password = form.children[1];"
562       "password.value = 'random';"
563       "form.children[2].click()";  // form.children[2] is the submit button.
564   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
565   observer.Wait();
566   EXPECT_FALSE(observer.infobar_shown());
567 }
568
569 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
570   NavigateToFile("/password/multi_frames.html");
571
572   NavigationObserver observer(WebContents());
573   // Make sure we save some password info from an iframe and then destroy it.
574   std::string save_and_remove =
575       "var first_frame = document.getElementById('first_frame');"
576       "var frame_doc = first_frame.contentDocument;"
577       "frame_doc.getElementById('username_field').value = 'temp';"
578       "frame_doc.getElementById('password_field').value = 'random';"
579       "frame_doc.getElementById('input_submit_button').click();"
580       "first_frame.parentNode.removeChild(first_frame);";
581   // Submit from the main frame, but without navigating through the onsubmit
582   // handler.
583   std::string navigate_frame =
584       "document.getElementById('username_field').value = 'temp';"
585       "document.getElementById('password_field').value = 'random';"
586       "document.getElementById('input_submit_button').click();"
587       "window.location.href = 'done.html';";
588
589   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), save_and_remove));
590   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
591   observer.Wait();
592   // The only thing we check here is that there is no use-after-free reported.
593 }
594
595 // Disabled on Windows due to flakiness: http://crbug.com/346297
596 #if defined(OS_WIN)
597 #define MAYBE_PasswordValueAccessible DISABLED_PasswordValueAccessible
598 #else
599 #define MAYBE_PasswordValueAccessible PasswordValueAccessible
600 #endif
601 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
602                        MAYBE_PasswordValueAccessible) {
603   NavigateToFile("/password/form_and_link.html");
604
605   // Click on a link to open a new tab, then switch back to the first one.
606   EXPECT_EQ(1, browser()->tab_strip_model()->count());
607   std::string click =
608       "document.getElementById('testlink').click();";
609   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), click));
610   EXPECT_EQ(2, browser()->tab_strip_model()->count());
611   browser()->tab_strip_model()->ActivateTabAt(0, false);
612
613   // Fill in the credentials, and make sure they are saved.
614   NavigationObserver form_submit_observer(WebContents());
615   std::string fill_and_submit =
616       "document.getElementById('username_field').value = 'temp';"
617       "document.getElementById('password_field').value = 'random';"
618       "document.getElementById('input_submit_button').click();";
619   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
620   form_submit_observer.Wait();
621   EXPECT_TRUE(form_submit_observer.infobar_shown());
622
623   // Reload the original page to have the saved credentials autofilled.
624   NavigationObserver reload_observer(WebContents());
625   NavigateToFile("/password/form_and_link.html");
626   reload_observer.Wait();
627
628   // Check that while the username is immediately available, the password value
629   // needs a user interaction to show up.
630   std::string check_username =
631       "document.getElementById('username_field').value == 'temp'";
632   std::string check_password =
633       "document.getElementById('password_field').value == 'random'";
634   CheckScriptReturnValue(check_username, true);
635   CheckScriptReturnValue(check_password, false);
636   content::SimulateMouseClick(
637       WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
638   CheckScriptReturnValue(check_username, true);
639   CheckScriptReturnValue(check_password, true);
640 }
641
642 // Test fix for crbug.com/338650.
643 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
644                        DontPromptForPasswordFormWithDefaultValue) {
645   NavigateToFile("/password/password_form_with_default_value.html");
646
647   // Don't prompt if we navigate away even if there is a password value since
648   // it's not coming from the user.
649   NavigationObserver observer(WebContents());
650   NavigateToFile("/password/done.html");
651   observer.Wait();
652   EXPECT_FALSE(observer.infobar_shown());
653 }
654
655 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
656                        PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
657   NavigateToFile("/password/password_form.html");
658
659   // Fill a form and submit through a <input type="submit"> button.
660   NavigationObserver observer(WebContents());
661   std::string fill_and_submit =
662       "document.getElementById('username_field').value = 'temp';"
663       "document.getElementById('password_field').value = 'random';"
664       "document.getElementById('input_submit_button').click()";
665   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
666   observer.Wait();
667   EXPECT_TRUE(observer.infobar_shown());
668 }
669
670 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
671                        DontPromptWhenEnableAutomaticPasswordSavingSwitchIsSet) {
672   password_manager::TestPasswordStore* password_store =
673       static_cast<password_manager::TestPasswordStore*>(
674           PasswordStoreFactory::GetForProfile(browser()->profile(),
675                                               Profile::IMPLICIT_ACCESS).get());
676
677   EXPECT_TRUE(password_store->IsEmpty());
678
679   NavigateToFile("/password/password_form.html");
680
681   // Add the enable-automatic-password-saving switch.
682   CommandLine::ForCurrentProcess()->AppendSwitch(
683       password_manager::switches::kEnableAutomaticPasswordSaving);
684
685   // Fill a form and submit through a <input type="submit"> button.
686   NavigationObserver observer(WebContents());
687   // Make sure that the only passwords saved are the auto-saved ones.
688   observer.disable_should_automatically_accept_infobar();
689   std::string fill_and_submit =
690       "document.getElementById('username_field').value = 'temp';"
691       "document.getElementById('password_field').value = 'random';"
692       "document.getElementById('input_submit_button').click()";
693   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
694   observer.Wait();
695   if (chrome::VersionInfo::GetChannel() ==
696       chrome::VersionInfo::CHANNEL_UNKNOWN) {
697     EXPECT_FALSE(observer.infobar_shown());
698     EXPECT_FALSE(password_store->IsEmpty());
699   } else {
700     EXPECT_TRUE(observer.infobar_shown());
701     EXPECT_TRUE(password_store->IsEmpty());
702   }
703 }
704
705 // Test fix for crbug.com/368690.
706 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
707   NavigateToFile("/password/password_form.html");
708
709   std::string fill =
710       "document.getElementById('username_redirect').value = 'temp';"
711       "document.getElementById('password_redirect').value = 'random';";
712   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
713
714   NavigationObserver observer(WebContents());
715   GURL url = embedded_test_server()->GetURL("/password/password_form.html");
716   chrome::NavigateParams params(browser(), url,
717                                 content::PAGE_TRANSITION_RELOAD);
718   ui_test_utils::NavigateToURL(&params);
719   observer.Wait();
720   EXPECT_FALSE(observer.infobar_shown());
721 }