Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / password_manager / password_manager_browsertest.cc
blob8f173de81c6f200e9a171f21f58bbe8dc42a7b65
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/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/infobars/infobar_service.h"
17 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
18 #include "chrome/browser/password_manager/password_store_factory.h"
19 #include "chrome/browser/password_manager/test_password_store_service.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/login/login_prompt.h"
22 #include "chrome/browser/ui/login/login_prompt_test_utils.h"
23 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/test/base/in_process_browser_test.h"
29 #include "chrome/test/base/test_switches.h"
30 #include "chrome/test/base/ui_test_utils.h"
31 #include "components/autofill/core/browser/autofill_test_utils.h"
32 #include "components/infobars/core/confirm_infobar_delegate.h"
33 #include "components/infobars/core/infobar.h"
34 #include "components/infobars/core/infobar_manager.h"
35 #include "components/password_manager/core/browser/test_password_store.h"
36 #include "components/password_manager/core/common/password_manager_switches.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/notification_service.h"
39 #include "content/public/browser/render_frame_host.h"
40 #include "content/public/browser/render_view_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_contents_observer.h"
43 #include "content/public/common/content_switches.h"
44 #include "content/public/test/browser_test_utils.h"
45 #include "content/public/test/test_utils.h"
46 #include "net/base/filename_util.h"
47 #include "net/test/embedded_test_server/embedded_test_server.h"
48 #include "net/test/embedded_test_server/http_request.h"
49 #include "net/test/embedded_test_server/http_response.h"
50 #include "net/test/spawned_test_server/spawned_test_server.h"
51 #include "net/url_request/test_url_fetcher_factory.h"
52 #include "testing/gmock/include/gmock/gmock.h"
53 #include "third_party/WebKit/public/web/WebInputEvent.h"
54 #include "ui/events/keycodes/keyboard_codes.h"
55 #include "ui/gfx/geometry/point.h"
58 // NavigationObserver ---------------------------------------------------------
60 namespace {
62 // Observer that waits for navigation to complete and for the password infobar
63 // to be shown.
64 class NavigationObserver : public content::WebContentsObserver {
65 public:
66 explicit NavigationObserver(content::WebContents* web_contents)
67 : content::WebContentsObserver(web_contents),
68 message_loop_runner_(new content::MessageLoopRunner) {}
70 virtual ~NavigationObserver() {}
72 // Normally Wait() will not return until a main frame navigation occurs.
73 // If a path is set, Wait() will return after this path has been seen,
74 // regardless of the frame that navigated. Useful for multi-frame pages.
75 void SetPathToWaitFor(const std::string& path) {
76 wait_for_path_ = path;
79 // content::WebContentsObserver:
80 virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
81 const GURL& validated_url) override {
82 if (!wait_for_path_.empty()) {
83 if (validated_url.path() == wait_for_path_)
84 message_loop_runner_->Quit();
85 } else if (!render_frame_host->GetParent()) {
86 message_loop_runner_->Quit();
90 void Wait() { message_loop_runner_->Run(); }
92 private:
93 std::string wait_for_path_;
94 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
96 DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
99 // Observes the save password prompt (bubble or infobar) for a specified
100 // WebContents, keeps track of whether or not it is currently shown, and allows
101 // accepting saving passwords through it.
102 class PromptObserver {
103 public:
104 virtual ~PromptObserver() {}
106 // Checks if the prompt is being currently shown.
107 virtual bool IsShowingPrompt() const = 0;
109 // Expecting that the prompt is shown, saves the password. Checks that the
110 // prompt is no longer visible afterwards.
111 void Accept() const {
112 EXPECT_TRUE(IsShowingPrompt());
113 AcceptImpl();
116 // Chooses the right implementation of PromptObserver and creates an instance
117 // of it.
118 static scoped_ptr<PromptObserver> Create(content::WebContents* web_contents);
120 protected:
121 PromptObserver() {}
123 // Accepts the password. The implementation can assume that the prompt is
124 // currently shown, but is required to verify that the prompt is eventually
125 // closed.
126 virtual void AcceptImpl() const = 0;
128 private:
129 DISALLOW_COPY_AND_ASSIGN(PromptObserver);
132 class InfoBarObserver : public PromptObserver,
133 public infobars::InfoBarManager::Observer {
134 public:
135 explicit InfoBarObserver(content::WebContents* web_contents)
136 : infobar_is_being_shown_(false),
137 infobar_service_(InfoBarService::FromWebContents(web_contents)) {
138 infobar_service_->AddObserver(this);
141 virtual ~InfoBarObserver() {
142 if (infobar_service_)
143 infobar_service_->RemoveObserver(this);
146 private:
147 // PromptObserver:
148 virtual bool IsShowingPrompt() const override {
149 return infobar_is_being_shown_;
152 virtual void AcceptImpl() const override {
153 EXPECT_EQ(1u, infobar_service_->infobar_count());
154 if (!infobar_service_->infobar_count())
155 return; // Let the test finish to gather possibly more diagnostics.
157 // ConfirmInfoBarDelegate::Accept returning true means the infobar is
158 // immediately closed. Checking the return value is preferred to testing
159 // IsShowingPrompt() here, for it avoids the delay until the closing
160 // notification is received.
161 EXPECT_TRUE(infobar_service_->infobar_at(0)
162 ->delegate()
163 ->AsConfirmInfoBarDelegate()
164 ->Accept());
167 // infobars::InfoBarManager::Observer:
168 virtual void OnInfoBarAdded(infobars::InfoBar* infobar) override {
169 infobar_is_being_shown_ = true;
172 virtual void OnInfoBarRemoved(infobars::InfoBar* infobar,
173 bool animate) override {
174 infobar_is_being_shown_ = false;
177 virtual void OnManagerShuttingDown(
178 infobars::InfoBarManager* manager) override {
179 ASSERT_EQ(infobar_service_, manager);
180 infobar_service_->RemoveObserver(this);
181 infobar_service_ = NULL;
184 bool infobar_is_being_shown_;
185 InfoBarService* infobar_service_;
187 DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
190 class BubbleObserver : public PromptObserver {
191 public:
192 explicit BubbleObserver(content::WebContents* web_contents)
193 : ui_controller_(
194 ManagePasswordsUIController::FromWebContents(web_contents)) {}
196 virtual ~BubbleObserver() {}
198 private:
199 // PromptObserver:
200 virtual bool IsShowingPrompt() const override {
201 return ui_controller_->PasswordPendingUserDecision();
204 virtual void AcceptImpl() const override {
205 ui_controller_->SavePassword();
206 EXPECT_FALSE(IsShowingPrompt());
209 ManagePasswordsUIController* const ui_controller_;
211 DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
214 GURL GetFileURL(const char* filename) {
215 base::FilePath path;
216 PathService::Get(chrome::DIR_TEST_DATA, &path);
217 path = path.AppendASCII("password").AppendASCII(filename);
218 CHECK(base::PathExists(path));
219 return net::FilePathToFileURL(path);
222 // static
223 scoped_ptr<PromptObserver> PromptObserver::Create(
224 content::WebContents* web_contents) {
225 if (ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled()) {
226 return scoped_ptr<PromptObserver>(new BubbleObserver(web_contents));
227 } else {
228 return scoped_ptr<PromptObserver>(new InfoBarObserver(web_contents));
232 // Handles |request| to "/basic_auth". If "Authorization" header is present,
233 // responds with a non-empty HTTP 200 page (regardless of its value). Otherwise
234 // serves a Basic Auth challenge.
235 scoped_ptr<net::test_server::HttpResponse> HandleTestAuthRequest(
236 const net::test_server::HttpRequest& request) {
237 if (!StartsWithASCII(request.relative_url, "/basic_auth", true))
238 return scoped_ptr<net::test_server::HttpResponse>();
240 if (ContainsKey(request.headers, "Authorization")) {
241 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
242 new net::test_server::BasicHttpResponse);
243 http_response->set_code(net::HTTP_OK);
244 http_response->set_content("Success!");
245 return http_response.Pass();
246 } else {
247 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
248 new net::test_server::BasicHttpResponse);
249 http_response->set_code(net::HTTP_UNAUTHORIZED);
250 http_response->AddCustomHeader("WWW-Authenticate",
251 "Basic realm=\"test realm\"");
252 return http_response.Pass();
256 } // namespace
259 // PasswordManagerBrowserTest -------------------------------------------------
261 class PasswordManagerBrowserTest : public InProcessBrowserTest {
262 public:
263 PasswordManagerBrowserTest() {}
264 virtual ~PasswordManagerBrowserTest() {}
266 // InProcessBrowserTest:
267 virtual void SetUpOnMainThread() override {
268 // Use TestPasswordStore to remove a possible race. Normally the
269 // PasswordStore does its database manipulation on the DB thread, which
270 // creates a possible race during navigation. Specifically the
271 // PasswordManager will ignore any forms in a page if the load from the
272 // PasswordStore has not completed.
273 PasswordStoreFactory::GetInstance()->SetTestingFactory(
274 browser()->profile(), TestPasswordStoreService::Build);
275 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
276 ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
277 password_manager::switches::kEnableAutomaticPasswordSaving));
280 virtual void TearDownOnMainThread() override {
281 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
284 protected:
285 content::WebContents* WebContents() {
286 return browser()->tab_strip_model()->GetActiveWebContents();
289 content::RenderViewHost* RenderViewHost() {
290 return WebContents()->GetRenderViewHost();
293 // Wrapper around ui_test_utils::NavigateToURL that waits until
294 // DidFinishLoad() fires. Normally this function returns after
295 // DidStopLoading(), which caused flakiness as the NavigationObserver
296 // would sometimes see the DidFinishLoad event from a previous navigation and
297 // return immediately.
298 void NavigateToFile(const std::string& path) {
299 NavigationObserver observer(WebContents());
300 GURL url = embedded_test_server()->GetURL(path);
301 ui_test_utils::NavigateToURL(browser(), url);
302 observer.Wait();
305 // Waits until the "value" attribute of the HTML element with |element_id| is
306 // equal to |expected_value|. If the current value is not as expected, this
307 // waits until the "change" event is fired for the element. This also
308 // guarantees that once the real value matches the expected, the JavaScript
309 // event loop is spun to allow all other possible events to take place.
310 void WaitForElementValue(const std::string& element_id,
311 const std::string& expected_value);
312 // Checks that the current "value" attribute of the HTML element with
313 // |element_id| is equal to |expected_value|.
314 void CheckElementValue(const std::string& element_id,
315 const std::string& expected_value);
317 private:
318 DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
321 void PasswordManagerBrowserTest::WaitForElementValue(
322 const std::string& element_id,
323 const std::string& expected_value) {
324 enum ReturnCodes { // Possible results of the JavaScript code.
325 RETURN_CODE_OK,
326 RETURN_CODE_NO_ELEMENT,
327 RETURN_CODE_WRONG_VALUE,
328 RETURN_CODE_INVALID,
330 const std::string value_check_function = base::StringPrintf(
331 "function valueCheck() {"
332 " var element = document.getElementById('%s');"
333 " return element && element.value == '%s';"
334 "}",
335 element_id.c_str(),
336 expected_value.c_str());
337 const std::string script =
338 value_check_function +
339 base::StringPrintf(
340 "if (valueCheck()) {"
341 " /* Spin the event loop with setTimeout. */"
342 " setTimeout(window.domAutomationController.send(%d), 0);"
343 "} else {"
344 " var element = document.getElementById('%s');"
345 " if (!element)"
346 " window.domAutomationController.send(%d);"
347 " element.onchange = function() {"
348 " if (valueCheck()) {"
349 " /* Spin the event loop with setTimeout. */"
350 " setTimeout(window.domAutomationController.send(%d), 0);"
351 " } else {"
352 " window.domAutomationController.send(%d);"
353 " }"
354 " };"
355 "}",
356 RETURN_CODE_OK,
357 element_id.c_str(),
358 RETURN_CODE_NO_ELEMENT,
359 RETURN_CODE_OK,
360 RETURN_CODE_WRONG_VALUE);
361 int return_value = RETURN_CODE_INVALID;
362 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
363 RenderViewHost(), script, &return_value));
364 EXPECT_EQ(RETURN_CODE_OK, return_value)
365 << "element_id = " << element_id
366 << ", expected_value = " << expected_value;
369 void PasswordManagerBrowserTest::CheckElementValue(
370 const std::string& element_id,
371 const std::string& expected_value) {
372 const std::string value_check_script = base::StringPrintf(
373 "var element = document.getElementById('%s');"
374 "window.domAutomationController.send(element && element.value == '%s');",
375 element_id.c_str(),
376 expected_value.c_str());
377 bool return_value = false;
378 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
379 RenderViewHost(), value_check_script, &return_value));
380 EXPECT_TRUE(return_value) << "element_id = " << element_id
381 << ", expected_value = " << expected_value;
384 // Actual tests ---------------------------------------------------------------
385 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
386 PromptForNormalSubmit) {
387 NavigateToFile("/password/password_form.html");
389 // Fill a form and submit through a <input type="submit"> button. Nothing
390 // special.
391 NavigationObserver observer(WebContents());
392 scoped_ptr<PromptObserver> prompt_observer(
393 PromptObserver::Create(WebContents()));
394 std::string fill_and_submit =
395 "document.getElementById('username_field').value = 'temp';"
396 "document.getElementById('password_field').value = 'random';"
397 "document.getElementById('input_submit_button').click()";
398 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
399 observer.Wait();
400 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
403 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
404 PromptForSubmitWithInPageNavigation) {
405 NavigateToFile("/password/password_navigate_before_submit.html");
407 // Fill a form and submit through a <input type="submit"> button. Nothing
408 // special. The form does an in-page navigation before submitting.
409 NavigationObserver observer(WebContents());
410 scoped_ptr<PromptObserver> prompt_observer(
411 PromptObserver::Create(WebContents()));
412 std::string fill_and_submit =
413 "document.getElementById('username_field').value = 'temp';"
414 "document.getElementById('password_field').value = 'random';"
415 "document.getElementById('input_submit_button').click()";
416 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
417 observer.Wait();
418 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
421 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
422 LoginSuccessWithUnrelatedForm) {
423 // Log in, see a form on the landing page. That form is not related to the
424 // login form (=has a different action), so we should offer saving the
425 // password.
426 NavigateToFile("/password/password_form.html");
428 NavigationObserver observer(WebContents());
429 scoped_ptr<PromptObserver> prompt_observer(
430 PromptObserver::Create(WebContents()));
431 std::string fill_and_submit =
432 "document.getElementById('username_unrelated').value = 'temp';"
433 "document.getElementById('password_unrelated').value = 'random';"
434 "document.getElementById('submit_unrelated').click()";
435 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
436 observer.Wait();
437 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
440 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, LoginFailed) {
441 // Log in, see a form on the landing page. That form is not related to the
442 // login form (=has a different action), so we should offer saving the
443 // password.
444 NavigateToFile("/password/password_form.html");
446 NavigationObserver observer(WebContents());
447 scoped_ptr<PromptObserver> prompt_observer(
448 PromptObserver::Create(WebContents()));
449 std::string fill_and_submit =
450 "document.getElementById('username_failed').value = 'temp';"
451 "document.getElementById('password_failed').value = 'random';"
452 "document.getElementById('submit_failed').click()";
453 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
454 observer.Wait();
455 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
458 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
459 NavigateToFile("/password/password_form.html");
461 // Fill a form and submit through a <input type="submit"> button. The form
462 // points to a redirection page.
463 NavigationObserver observer(WebContents());
464 scoped_ptr<PromptObserver> prompt_observer(
465 PromptObserver::Create(WebContents()));
466 std::string fill_and_submit =
467 "document.getElementById('username_redirect').value = 'temp';"
468 "document.getElementById('password_redirect').value = 'random';"
469 "document.getElementById('submit_redirect').click()";
470 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
471 observer.Wait();
472 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
474 // The redirection page now redirects via Javascript. We check that the
475 // infobar stays.
476 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
477 "window.location.href = 'done.html';"));
478 observer.Wait();
479 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
482 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
483 PromptForSubmitUsingJavaScript) {
484 NavigateToFile("/password/password_form.html");
486 // Fill a form and submit using <button> that calls submit() on the form.
487 // This should work regardless of the type of element, as long as submit() is
488 // called.
489 NavigationObserver observer(WebContents());
490 scoped_ptr<PromptObserver> prompt_observer(
491 PromptObserver::Create(WebContents()));
492 std::string fill_and_submit =
493 "document.getElementById('username_field').value = 'temp';"
494 "document.getElementById('password_field').value = 'random';"
495 "document.getElementById('submit_button').click()";
496 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
497 observer.Wait();
498 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
501 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
502 // platforms.
503 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
504 DISABLED_PromptForDynamicForm) {
505 NavigateToFile("/password/dynamic_password_form.html");
507 // Fill the dynamic password form and submit.
508 NavigationObserver observer(WebContents());
509 scoped_ptr<PromptObserver> prompt_observer(
510 PromptObserver::Create(WebContents()));
511 std::string fill_and_submit =
512 "document.getElementById('create_form_button').click();"
513 "window.setTimeout(function() {"
514 " document.dynamic_form.username.value = 'tempro';"
515 " document.dynamic_form.password.value = 'random';"
516 " document.dynamic_form.submit();"
517 "}, 0)";
518 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
519 observer.Wait();
520 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
523 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
524 NavigateToFile("/password/password_form.html");
526 // Don't fill the password form, just navigate away. Shouldn't prompt.
527 NavigationObserver observer(WebContents());
528 scoped_ptr<PromptObserver> prompt_observer(
529 PromptObserver::Create(WebContents()));
530 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
531 "window.location.href = 'done.html';"));
532 observer.Wait();
533 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
536 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
537 NoPromptForSubFrameNavigation) {
538 NavigateToFile("/password/multi_frames.html");
540 // If you are filling out a password form in one frame and a different frame
541 // navigates, this should not trigger the infobar.
542 NavigationObserver observer(WebContents());
543 scoped_ptr<PromptObserver> prompt_observer(
544 PromptObserver::Create(WebContents()));
545 observer.SetPathToWaitFor("/password/done.html");
546 std::string fill =
547 "var first_frame = document.getElementById('first_frame');"
548 "var frame_doc = first_frame.contentDocument;"
549 "frame_doc.getElementById('username_field').value = 'temp';"
550 "frame_doc.getElementById('password_field').value = 'random';";
551 std::string navigate_frame =
552 "var second_iframe = document.getElementById('second_frame');"
553 "second_iframe.contentWindow.location.href = 'done.html';";
555 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
556 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
557 observer.Wait();
558 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
561 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
562 PromptAfterSubmitWithSubFrameNavigation) {
563 NavigateToFile("/password/multi_frames.html");
565 // Make sure that we prompt to save password even if a sub-frame navigation
566 // happens first.
567 NavigationObserver observer(WebContents());
568 scoped_ptr<PromptObserver> prompt_observer(
569 PromptObserver::Create(WebContents()));
570 observer.SetPathToWaitFor("/password/done.html");
571 std::string navigate_frame =
572 "var second_iframe = document.getElementById('second_frame');"
573 "second_iframe.contentWindow.location.href = 'other.html';";
574 std::string fill_and_submit =
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();";
581 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
582 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
583 observer.Wait();
584 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
587 IN_PROC_BROWSER_TEST_F(
588 PasswordManagerBrowserTest,
589 NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage) {
590 NavigateToFile("/password/multi_frames.html");
592 // Make sure that we don't prompt to save the password for a failed login
593 // from the main frame with multiple frames in the same page.
594 NavigationObserver observer(WebContents());
595 scoped_ptr<PromptObserver> prompt_observer(
596 PromptObserver::Create(WebContents()));
597 std::string fill_and_submit =
598 "document.getElementById('username_failed').value = 'temp';"
599 "document.getElementById('password_failed').value = 'random';"
600 "document.getElementById('submit_failed').click();";
602 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
603 observer.Wait();
604 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
607 IN_PROC_BROWSER_TEST_F(
608 PasswordManagerBrowserTest,
609 NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage) {
610 NavigateToFile("/password/multi_frames.html");
612 // Make sure that we don't prompt to save the password for a failed login
613 // from a sub-frame with multiple frames in the same page.
614 NavigationObserver observer(WebContents());
615 scoped_ptr<PromptObserver> prompt_observer(
616 PromptObserver::Create(WebContents()));
617 std::string fill_and_submit =
618 "var first_frame = document.getElementById('first_frame');"
619 "var frame_doc = first_frame.contentDocument;"
620 "frame_doc.getElementById('username_failed').value = 'temp';"
621 "frame_doc.getElementById('password_failed').value = 'random';"
622 "frame_doc.getElementById('submit_failed').click();"
623 "window.parent.location.href = 'multi_frames.html';";
625 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
626 observer.Wait();
627 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
630 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
631 #if defined(OS_WIN) && defined(USE_ASH)
632 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
633 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
634 return;
635 #endif
636 NavigateToFile("/password/password_xhr_submit.html");
638 // Verify that we show the save password prompt if a form returns false
639 // in its onsubmit handler but instead logs in/navigates via XHR.
640 // Note that calling 'submit()' on a form with javascript doesn't call
641 // the onsubmit handler, so we click the submit button instead.
642 NavigationObserver observer(WebContents());
643 scoped_ptr<PromptObserver> prompt_observer(
644 PromptObserver::Create(WebContents()));
645 std::string fill_and_submit =
646 "document.getElementById('username_field').value = 'temp';"
647 "document.getElementById('password_field').value = 'random';"
648 "document.getElementById('submit_button').click()";
649 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
650 observer.Wait();
651 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
654 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
655 PromptForXHRWithoutOnSubmit) {
656 NavigateToFile("/password/password_xhr_submit.html");
658 // Verify that if XHR navigation occurs and the form is properly filled out,
659 // we try and save the password even though onsubmit hasn't been called.
660 NavigationObserver observer(WebContents());
661 scoped_ptr<PromptObserver> prompt_observer(
662 PromptObserver::Create(WebContents()));
663 std::string fill_and_navigate =
664 "document.getElementById('username_field').value = 'temp';"
665 "document.getElementById('password_field').value = 'random';"
666 "send_xhr()";
667 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
668 observer.Wait();
669 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
672 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfLinkClicked) {
673 NavigateToFile("/password/password_form.html");
675 // Verify that if the user takes a direct action to leave the page, we don't
676 // prompt to save the password even if the form is already filled out.
677 NavigationObserver observer(WebContents());
678 scoped_ptr<PromptObserver> prompt_observer(
679 PromptObserver::Create(WebContents()));
680 std::string fill_and_click_link =
681 "document.getElementById('username_field').value = 'temp';"
682 "document.getElementById('password_field').value = 'random';"
683 "document.getElementById('link').click();";
684 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link));
685 observer.Wait();
686 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
689 // TODO(jam): http://crbug.com/350550
690 #if !defined(OS_WIN)
691 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
692 VerifyPasswordGenerationUpload) {
693 // Prevent Autofill requests from actually going over the wire.
694 net::TestURLFetcherFactory factory;
695 // Disable Autofill requesting access to AddressBook data. This causes
696 // the test to hang on Mac.
697 autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
699 // Visit a signup form.
700 NavigateToFile("/password/signup_form.html");
702 // Enter a password and save it.
703 NavigationObserver first_observer(WebContents());
704 scoped_ptr<PromptObserver> prompt_observer(
705 PromptObserver::Create(WebContents()));
706 std::string fill_and_submit =
707 "document.getElementById('other_info').value = 'stuff';"
708 "document.getElementById('username_field').value = 'my_username';"
709 "document.getElementById('password_field').value = 'password';"
710 "document.getElementById('input_submit_button').click()";
711 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
713 first_observer.Wait();
714 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
715 prompt_observer->Accept();
717 // Now navigate to a login form that has similar HTML markup.
718 NavigateToFile("/password/password_form.html");
720 // Simulate a user click to force an autofill of the form's DOM value, not
721 // just the suggested value.
722 content::SimulateMouseClick(
723 WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
725 // The form should be filled with the previously submitted username.
726 std::string get_username =
727 "window.domAutomationController.send("
728 "document.getElementById('username_field').value);";
729 std::string actual_username;
730 ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
731 get_username,
732 &actual_username));
733 ASSERT_EQ("my_username", actual_username);
735 // Submit the form and verify that there is no infobar (as the password
736 // has already been saved).
737 NavigationObserver second_observer(WebContents());
738 scoped_ptr<PromptObserver> second_prompt_observer(
739 PromptObserver::Create(WebContents()));
740 std::string submit_form =
741 "document.getElementById('input_submit_button').click()";
742 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form));
743 second_observer.Wait();
744 EXPECT_FALSE(second_prompt_observer->IsShowingPrompt());
746 // Verify that we sent two pings to Autofill. One vote for of PASSWORD for
747 // the current form, and one vote for ACCOUNT_CREATION_PASSWORD on the
748 // original form since it has more than 2 text input fields and was used for
749 // the first time on a different form.
750 base::HistogramBase* upload_histogram =
751 base::StatisticsRecorder::FindHistogram(
752 "PasswordGeneration.UploadStarted");
753 ASSERT_TRUE(upload_histogram);
754 scoped_ptr<base::HistogramSamples> snapshot =
755 upload_histogram->SnapshotSamples();
756 EXPECT_EQ(0, snapshot->GetCount(0 /* failure */));
757 EXPECT_EQ(2, snapshot->GetCount(1 /* success */));
759 #endif
761 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
762 NavigateToFile("/password/password_submit_from_iframe.html");
764 // Submit a form in an iframe, then cause the whole page to navigate without a
765 // user gesture. We expect the save password prompt to be shown here, because
766 // some pages use such iframes for login forms.
767 NavigationObserver observer(WebContents());
768 scoped_ptr<PromptObserver> prompt_observer(
769 PromptObserver::Create(WebContents()));
770 std::string fill_and_submit =
771 "var iframe = document.getElementById('test_iframe');"
772 "var iframe_doc = iframe.contentDocument;"
773 "iframe_doc.getElementById('username_field').value = 'temp';"
774 "iframe_doc.getElementById('password_field').value = 'random';"
775 "iframe_doc.getElementById('submit_button').click()";
777 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
778 observer.Wait();
779 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
782 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
783 PromptForInputElementWithoutName) {
784 // Check that the prompt is shown for forms where input elements lack the
785 // "name" attribute but the "id" is present.
786 NavigateToFile("/password/password_form.html");
788 NavigationObserver observer(WebContents());
789 scoped_ptr<PromptObserver> prompt_observer(
790 PromptObserver::Create(WebContents()));
791 std::string fill_and_submit =
792 "document.getElementById('username_field_no_name').value = 'temp';"
793 "document.getElementById('password_field_no_name').value = 'random';"
794 "document.getElementById('input_submit_button_no_name').click()";
795 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
796 observer.Wait();
797 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
800 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
801 PromptForInputElementWithoutId) {
802 // Check that the prompt is shown for forms where input elements lack the
803 // "id" attribute but the "name" attribute is present.
804 NavigateToFile("/password/password_form.html");
806 NavigationObserver observer(WebContents());
807 scoped_ptr<PromptObserver> prompt_observer(
808 PromptObserver::Create(WebContents()));
809 std::string fill_and_submit =
810 "document.getElementsByName('username_field_no_id')[0].value = 'temp';"
811 "document.getElementsByName('password_field_no_id')[0].value = 'random';"
812 "document.getElementsByName('input_submit_button_no_id')[0].click()";
813 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
814 observer.Wait();
815 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
818 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
819 NoPromptForInputElementWithoutIdAndName) {
820 // Check that no prompt is shown for forms where the input fields lack both
821 // the "id" and the "name" attributes.
822 NavigateToFile("/password/password_form.html");
824 NavigationObserver observer(WebContents());
825 scoped_ptr<PromptObserver> prompt_observer(
826 PromptObserver::Create(WebContents()));
827 std::string fill_and_submit =
828 "var form = document.getElementById('testform_elements_no_id_no_name');"
829 "var username = form.children[0];"
830 "username.value = 'temp';"
831 "var password = form.children[1];"
832 "password.value = 'random';"
833 "form.children[2].click()"; // form.children[2] is the submit button.
834 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
835 observer.Wait();
836 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
839 // Test for checking that no prompt is shown for URLs with file: scheme.
840 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
841 NoPromptForFileSchemeURLs) {
842 GURL url = GetFileURL("password_form.html");
843 ui_test_utils::NavigateToURL(browser(), url);
845 NavigationObserver observer(WebContents());
846 scoped_ptr<PromptObserver> prompt_observer(
847 PromptObserver::Create(WebContents()));
848 std::string fill_and_submit =
849 "document.getElementById('username_field').value = 'temp';"
850 "document.getElementById('password_field').value = 'random';"
851 "document.getElementById('input_submit_button').click();";
852 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
853 observer.Wait();
854 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
857 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
858 NavigateToFile("/password/multi_frames.html");
860 NavigationObserver observer(WebContents());
861 // Make sure we save some password info from an iframe and then destroy it.
862 std::string save_and_remove =
863 "var first_frame = document.getElementById('first_frame');"
864 "var frame_doc = first_frame.contentDocument;"
865 "frame_doc.getElementById('username_field').value = 'temp';"
866 "frame_doc.getElementById('password_field').value = 'random';"
867 "frame_doc.getElementById('input_submit_button').click();"
868 "first_frame.parentNode.removeChild(first_frame);";
869 // Submit from the main frame, but without navigating through the onsubmit
870 // handler.
871 std::string navigate_frame =
872 "document.getElementById('username_field').value = 'temp';"
873 "document.getElementById('password_field').value = 'random';"
874 "document.getElementById('input_submit_button').click();"
875 "window.location.href = 'done.html';";
877 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), save_and_remove));
878 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
879 observer.Wait();
880 // The only thing we check here is that there is no use-after-free reported.
883 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PasswordValueAccessible) {
884 NavigateToFile("/password/form_and_link.html");
886 // Click on a link to open a new tab, then switch back to the first one.
887 EXPECT_EQ(1, browser()->tab_strip_model()->count());
888 std::string click =
889 "document.getElementById('testlink').click();";
890 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), click));
891 EXPECT_EQ(2, browser()->tab_strip_model()->count());
892 browser()->tab_strip_model()->ActivateTabAt(0, false);
894 // Fill in the credentials, and make sure they are saved.
895 NavigationObserver form_submit_observer(WebContents());
896 scoped_ptr<PromptObserver> prompt_observer(
897 PromptObserver::Create(WebContents()));
898 std::string fill_and_submit =
899 "document.getElementById('username_field').value = 'temp';"
900 "document.getElementById('password_field').value = 'random';"
901 "document.getElementById('input_submit_button').click();";
902 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
903 form_submit_observer.Wait();
904 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
905 prompt_observer->Accept();
907 // Reload the original page to have the saved credentials autofilled.
908 NavigationObserver reload_observer(WebContents());
909 NavigateToFile("/password/form_and_link.html");
910 reload_observer.Wait();
912 // Wait until the username is filled, to make sure autofill kicked in.
913 WaitForElementValue("username_field", "temp");
914 // Now check that the password is not accessible yet.
915 CheckElementValue("password_field", "");
916 // Let the user interact with the page.
917 content::SimulateMouseClickAt(
918 WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(1, 1));
919 // Wait until that interaction causes the password value to be revealed.
920 WaitForElementValue("password_field", "random");
921 // And check that after the side-effects of the interaction took place, the
922 // username value stays the same.
923 CheckElementValue("username_field", "temp");
926 // The following test is limited to Aura, because
927 // RenderWidgetHostViewGuest::ProcessAckedTouchEvent is, and
928 // ProcessAckedTouchEvent is what triggers the translation of touch events to
929 // gesture events.
930 #if defined(USE_AURA)
931 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
932 PasswordValueAccessibleOnSubmit) {
933 NavigateToFile("/password/form_and_link.html");
935 // Fill in the credentials, and make sure they are saved.
936 NavigationObserver form_submit_observer(WebContents());
937 scoped_ptr<PromptObserver> prompt_observer(
938 PromptObserver::Create(WebContents()));
939 std::string fill_and_submit =
940 "document.getElementById('username_field').value = 'temp';"
941 "document.getElementById('password_field').value = 'random_secret';"
942 "document.getElementById('input_submit_button').click();";
943 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
944 form_submit_observer.Wait();
945 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
946 prompt_observer->Accept();
948 // Reload the original page to have the saved credentials autofilled.
949 NavigationObserver reload_observer(WebContents());
950 NavigateToFile("/password/form_and_link.html");
951 reload_observer.Wait();
953 NavigationObserver submit_observer(WebContents());
954 // Submit the form via a tap on the submit button. The button is placed at 0,
955 // 100, and has height 300 and width 700.
956 content::SimulateTapAt(WebContents(), gfx::Point(350, 250));
957 submit_observer.Wait();
958 std::string query = WebContents()->GetURL().query();
959 EXPECT_NE(std::string::npos, query.find("random_secret")) << query;
961 #endif
963 // Test fix for crbug.com/338650.
964 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
965 DontPromptForPasswordFormWithDefaultValue) {
966 NavigateToFile("/password/password_form_with_default_value.html");
968 // Don't prompt if we navigate away even if there is a password value since
969 // it's not coming from the user.
970 NavigationObserver observer(WebContents());
971 scoped_ptr<PromptObserver> prompt_observer(
972 PromptObserver::Create(WebContents()));
973 NavigateToFile("/password/done.html");
974 observer.Wait();
975 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
978 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
979 PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
980 NavigateToFile("/password/password_form.html");
982 // Fill a form and submit through a <input type="submit"> button.
983 NavigationObserver observer(WebContents());
984 scoped_ptr<PromptObserver> prompt_observer(
985 PromptObserver::Create(WebContents()));
986 std::string fill_and_submit =
987 "document.getElementById('username_field').value = 'temp';"
988 "document.getElementById('password_field').value = 'random';"
989 "document.getElementById('input_submit_button').click()";
990 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
991 observer.Wait();
992 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
995 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
996 DontPromptWhenEnableAutomaticPasswordSavingSwitchIsSet) {
997 password_manager::TestPasswordStore* password_store =
998 static_cast<password_manager::TestPasswordStore*>(
999 PasswordStoreFactory::GetForProfile(browser()->profile(),
1000 Profile::IMPLICIT_ACCESS).get());
1002 EXPECT_TRUE(password_store->IsEmpty());
1004 NavigateToFile("/password/password_form.html");
1006 // Add the enable-automatic-password-saving switch.
1007 CommandLine::ForCurrentProcess()->AppendSwitch(
1008 password_manager::switches::kEnableAutomaticPasswordSaving);
1010 // Fill a form and submit through a <input type="submit"> button.
1011 NavigationObserver observer(WebContents());
1012 scoped_ptr<PromptObserver> prompt_observer(
1013 PromptObserver::Create(WebContents()));
1014 // Make sure that the only passwords saved are the auto-saved ones.
1015 std::string fill_and_submit =
1016 "document.getElementById('username_field').value = 'temp';"
1017 "document.getElementById('password_field').value = 'random';"
1018 "document.getElementById('input_submit_button').click()";
1019 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
1020 observer.Wait();
1021 if (chrome::VersionInfo::GetChannel() ==
1022 chrome::VersionInfo::CHANNEL_UNKNOWN) {
1023 // Passwords getting auto-saved, no prompt.
1024 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1025 EXPECT_FALSE(password_store->IsEmpty());
1026 } else {
1027 // Prompt shown, and no passwords saved automatically.
1028 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1029 EXPECT_TRUE(password_store->IsEmpty());
1033 // Test fix for crbug.com/368690.
1034 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
1035 NavigateToFile("/password/password_form.html");
1037 std::string fill =
1038 "document.getElementById('username_redirect').value = 'temp';"
1039 "document.getElementById('password_redirect').value = 'random';";
1040 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
1042 NavigationObserver observer(WebContents());
1043 scoped_ptr<PromptObserver> prompt_observer(
1044 PromptObserver::Create(WebContents()));
1045 GURL url = embedded_test_server()->GetURL("/password/password_form.html");
1046 chrome::NavigateParams params(browser(), url,
1047 ui::PAGE_TRANSITION_RELOAD);
1048 ui_test_utils::NavigateToURL(&params);
1049 observer.Wait();
1050 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1053 // Test that if a form gets dynamically added between the form parsing and
1054 // rendering, and while the main frame still loads, it still is registered, and
1055 // thus saving passwords from it works.
1056 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1057 FormsAddedBetweenParsingAndRendering) {
1058 NavigateToFile("/password/between_parsing_and_rendering.html");
1060 NavigationObserver observer(WebContents());
1061 scoped_ptr<PromptObserver> prompt_observer(
1062 PromptObserver::Create(WebContents()));
1063 std::string submit =
1064 "document.getElementById('username').value = 'temp';"
1065 "document.getElementById('password').value = 'random';"
1066 "document.getElementById('submit-button').click();";
1067 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1068 observer.Wait();
1070 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1073 // Test that if there was no previous page load then the PasswordManagerDriver
1074 // does not think that there were SSL errors on the current page. The test opens
1075 // a new tab with a URL for which the embedded test server issues a basic auth
1076 // challenge.
1077 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoLastLoadGoodLastLoad) {
1078 // Teach the embedded server to handle requests by issuing the basic auth
1079 // challenge.
1080 embedded_test_server()->RegisterRequestHandler(
1081 base::Bind(&HandleTestAuthRequest));
1083 LoginPromptBrowserTestObserver login_observer;
1084 // We need to register to all sources, because the navigation observer we are
1085 // interested in is for a new tab to be opened, and thus does not exist yet.
1086 login_observer.Register(content::NotificationService::AllSources());
1088 password_manager::TestPasswordStore* password_store =
1089 static_cast<password_manager::TestPasswordStore*>(
1090 PasswordStoreFactory::GetForProfile(browser()->profile(),
1091 Profile::IMPLICIT_ACCESS).get());
1092 EXPECT_TRUE(password_store->IsEmpty());
1094 // Navigate to a page requiring HTTP auth. Wait for the tab to get the correct
1095 // WebContents, but don't wait for navigation, which only finishes after
1096 // authentication.
1097 ui_test_utils::NavigateToURLWithDisposition(
1098 browser(),
1099 embedded_test_server()->GetURL("/basic_auth"),
1100 NEW_FOREGROUND_TAB,
1101 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
1103 content::NavigationController* nav_controller =
1104 &WebContents()->GetController();
1105 NavigationObserver nav_observer(WebContents());
1106 scoped_ptr<PromptObserver> prompt_observer(
1107 PromptObserver::Create(WebContents()));
1108 WindowedAuthNeededObserver auth_needed_observer(nav_controller);
1109 auth_needed_observer.Wait();
1111 WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
1112 // Offer valid credentials on the auth challenge.
1113 ASSERT_EQ(1u, login_observer.handlers().size());
1114 LoginHandler* handler = *login_observer.handlers().begin();
1115 ASSERT_TRUE(handler);
1116 // Any username/password will work.
1117 handler->SetAuth(base::UTF8ToUTF16("user"), base::UTF8ToUTF16("pwd"));
1118 auth_supplied_observer.Wait();
1120 // The password manager should be working correctly.
1121 nav_observer.Wait();
1122 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1123 prompt_observer->Accept();
1125 // Spin the message loop to make sure the password store had a chance to save
1126 // the password.
1127 base::RunLoop run_loop;
1128 run_loop.RunUntilIdle();
1129 EXPECT_FALSE(password_store->IsEmpty());
1132 // In some situations, multiple PasswordFormManager instances from
1133 // PasswordManager::pending_login_managers_ would match (via DoesManage) a form
1134 // to be provisionally saved. One of them might be a complete match, the other
1135 // all-but-action match. Normally, the former should be preferred, but if the
1136 // former has not finished matching, and the latter has, the latter should be
1137 // used (otherwise we'd give up even though we could have saved the password).
1138 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1139 PreferPasswordFormManagerWhichFinishedMatching) {
1140 NavigateToFile("/password/create_form_copy_on_submit.html");
1142 NavigationObserver observer(WebContents());
1143 scoped_ptr<PromptObserver> prompt_observer(
1144 PromptObserver::Create(WebContents()));
1145 std::string submit =
1146 "document.getElementById('username').value = 'overwrite_me';"
1147 "document.getElementById('password').value = 'random';"
1148 "document.getElementById('non-form-button').click();";
1149 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1150 observer.Wait();
1152 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1155 // Test that if login fails and content server pushes a different login form
1156 // with action URL having different schemes. Heuristic shall be able
1157 // identify such cases and *shall not* prompt to save incorrect password.
1158 IN_PROC_BROWSER_TEST_F(
1159 PasswordManagerBrowserTest,
1160 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpToHttps) {
1161 std::string path =
1162 "/password/separate_login_form_with_onload_submit_script.html";
1163 GURL http_url(embedded_test_server()->GetURL(path));
1164 ASSERT_TRUE(http_url.SchemeIs(url::kHttpScheme));
1166 NavigationObserver observer(WebContents());
1167 scoped_ptr<PromptObserver> prompt_observer(
1168 PromptObserver::Create(WebContents()));
1169 ui_test_utils::NavigateToURL(browser(), http_url);
1171 observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1172 observer.Wait();
1174 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1177 IN_PROC_BROWSER_TEST_F(
1178 PasswordManagerBrowserTest,
1179 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpsToHttp) {
1180 CommandLine::ForCurrentProcess()->AppendSwitch(
1181 switches::kAllowRunningInsecureContent);
1182 CommandLine::ForCurrentProcess()->AppendSwitch(
1183 switches::kIgnoreCertificateErrors);
1184 const base::FilePath::CharType kDocRoot[] =
1185 FILE_PATH_LITERAL("chrome/test/data");
1186 net::SpawnedTestServer https_test_server(
1187 net::SpawnedTestServer::TYPE_HTTPS,
1188 net::SpawnedTestServer::SSLOptions(
1189 net::SpawnedTestServer::SSLOptions::CERT_OK),
1190 base::FilePath(kDocRoot));
1191 ASSERT_TRUE(https_test_server.Start());
1193 // This test case cannot inject the scripts via content::ExecuteScript() in
1194 // files served through HTTPS. Therefore the scripts are made part of the HTML
1195 // site and executed on load.
1196 std::string path =
1197 "password/separate_login_form_with_onload_submit_script.html";
1198 GURL https_url(https_test_server.GetURL(path));
1199 ASSERT_TRUE(https_url.SchemeIs(url::kHttpsScheme));
1201 NavigationObserver observer(WebContents());
1202 scoped_ptr<PromptObserver> prompt_observer(
1203 PromptObserver::Create(WebContents()));
1204 ui_test_utils::NavigateToURL(browser(), https_url);
1206 observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1207 observer.Wait();
1209 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1212 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1213 PromptWhenPasswordFormWithoutUsernameFieldSubmitted) {
1214 password_manager::TestPasswordStore* password_store =
1215 static_cast<password_manager::TestPasswordStore*>(
1216 PasswordStoreFactory::GetForProfile(browser()->profile(),
1217 Profile::IMPLICIT_ACCESS).get());
1219 EXPECT_TRUE(password_store->IsEmpty());
1221 NavigateToFile("/password/form_with_only_password_field.html");
1223 NavigationObserver observer(WebContents());
1224 scoped_ptr<PromptObserver> prompt_observer(
1225 PromptObserver::Create(WebContents()));
1226 std::string submit =
1227 "document.getElementById('password').value = 'password';"
1228 "document.getElementById('submit-button').click();";
1229 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1230 observer.Wait();
1232 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1233 prompt_observer->Accept();
1235 // Spin the message loop to make sure the password store had a chance to save
1236 // the password.
1237 base::RunLoop run_loop;
1238 run_loop.RunUntilIdle();
1239 EXPECT_FALSE(password_store->IsEmpty());
1242 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1243 AutofillSuggetionsForPasswordFormWithoutUsernameField) {
1244 password_manager::TestPasswordStore* password_store =
1245 static_cast<password_manager::TestPasswordStore*>(
1246 PasswordStoreFactory::GetForProfile(browser()->profile(),
1247 Profile::IMPLICIT_ACCESS).get());
1249 EXPECT_TRUE(password_store->IsEmpty());
1251 // Password form without username-field.
1252 NavigateToFile("/password/form_with_only_password_field.html");
1254 NavigationObserver observer(WebContents());
1255 scoped_ptr<PromptObserver> prompt_observer(
1256 PromptObserver::Create(WebContents()));
1257 std::string submit =
1258 "document.getElementById('password').value = 'mypassword';"
1259 "document.getElementById('submit-button').click();";
1260 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1261 observer.Wait();
1263 prompt_observer->Accept();
1265 // Spin the message loop to make sure the password store had a chance to save
1266 // the password.
1267 base::RunLoop run_loop;
1268 run_loop.RunUntilIdle();
1269 EXPECT_FALSE(password_store->IsEmpty());
1271 // Now, navigate to same html password form and verify whether password is
1272 // autofilled.
1273 NavigateToFile("/password/form_with_only_password_field.html");
1275 // Let the user interact with the page, so that DOM gets modification events,
1276 // needed for autofilling fields.
1277 content::SimulateMouseClickAt(
1278 WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(1, 1));
1280 // Wait until that interaction causes the password value to be revealed.
1281 WaitForElementValue("password", "mypassword");