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.
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 ---------------------------------------------------------
62 // Observer that waits for navigation to complete and for the password infobar
64 class NavigationObserver
: public content::WebContentsObserver
{
66 explicit NavigationObserver(content::WebContents
* web_contents
)
67 : content::WebContentsObserver(web_contents
),
68 message_loop_runner_(new content::MessageLoopRunner
) {}
70 ~NavigationObserver() override
{}
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 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(); }
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
{
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());
116 // Chooses the right implementation of PromptObserver and creates an instance
118 static scoped_ptr
<PromptObserver
> Create(content::WebContents
* web_contents
);
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
126 virtual void AcceptImpl() const = 0;
129 DISALLOW_COPY_AND_ASSIGN(PromptObserver
);
132 class InfoBarObserver
: public PromptObserver
,
133 public infobars::InfoBarManager::Observer
{
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 ~InfoBarObserver() override
{
142 if (infobar_service_
)
143 infobar_service_
->RemoveObserver(this);
148 bool IsShowingPrompt() const override
{ return infobar_is_being_shown_
; }
150 void AcceptImpl() const override
{
151 EXPECT_EQ(1u, infobar_service_
->infobar_count());
152 if (!infobar_service_
->infobar_count())
153 return; // Let the test finish to gather possibly more diagnostics.
155 // ConfirmInfoBarDelegate::Accept returning true means the infobar is
156 // immediately closed. Checking the return value is preferred to testing
157 // IsShowingPrompt() here, for it avoids the delay until the closing
158 // notification is received.
159 EXPECT_TRUE(infobar_service_
->infobar_at(0)
161 ->AsConfirmInfoBarDelegate()
165 // infobars::InfoBarManager::Observer:
166 void OnInfoBarAdded(infobars::InfoBar
* infobar
) override
{
167 infobar_is_being_shown_
= true;
170 void OnInfoBarRemoved(infobars::InfoBar
* infobar
, bool animate
) override
{
171 infobar_is_being_shown_
= false;
174 void OnManagerShuttingDown(infobars::InfoBarManager
* manager
) override
{
175 ASSERT_EQ(infobar_service_
, manager
);
176 infobar_service_
->RemoveObserver(this);
177 infobar_service_
= NULL
;
180 bool infobar_is_being_shown_
;
181 InfoBarService
* infobar_service_
;
183 DISALLOW_COPY_AND_ASSIGN(InfoBarObserver
);
186 class BubbleObserver
: public PromptObserver
{
188 explicit BubbleObserver(content::WebContents
* web_contents
)
190 ManagePasswordsUIController::FromWebContents(web_contents
)) {}
192 ~BubbleObserver() override
{}
196 bool IsShowingPrompt() const override
{
197 return ui_controller_
->PasswordPendingUserDecision();
200 void AcceptImpl() const override
{
201 ui_controller_
->SavePassword();
202 EXPECT_FALSE(IsShowingPrompt());
205 ManagePasswordsUIController
* const ui_controller_
;
207 DISALLOW_COPY_AND_ASSIGN(BubbleObserver
);
210 GURL
GetFileURL(const char* filename
) {
212 PathService::Get(chrome::DIR_TEST_DATA
, &path
);
213 path
= path
.AppendASCII("password").AppendASCII(filename
);
214 CHECK(base::PathExists(path
));
215 return net::FilePathToFileURL(path
);
219 scoped_ptr
<PromptObserver
> PromptObserver::Create(
220 content::WebContents
* web_contents
) {
221 if (ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled()) {
222 return scoped_ptr
<PromptObserver
>(new BubbleObserver(web_contents
));
224 return scoped_ptr
<PromptObserver
>(new InfoBarObserver(web_contents
));
228 // Handles |request| to "/basic_auth". If "Authorization" header is present,
229 // responds with a non-empty HTTP 200 page (regardless of its value). Otherwise
230 // serves a Basic Auth challenge.
231 scoped_ptr
<net::test_server::HttpResponse
> HandleTestAuthRequest(
232 const net::test_server::HttpRequest
& request
) {
233 if (!StartsWithASCII(request
.relative_url
, "/basic_auth", true))
234 return scoped_ptr
<net::test_server::HttpResponse
>();
236 if (ContainsKey(request
.headers
, "Authorization")) {
237 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
238 new net::test_server::BasicHttpResponse
);
239 http_response
->set_code(net::HTTP_OK
);
240 http_response
->set_content("Success!");
241 return http_response
.Pass();
243 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
244 new net::test_server::BasicHttpResponse
);
245 http_response
->set_code(net::HTTP_UNAUTHORIZED
);
246 http_response
->AddCustomHeader("WWW-Authenticate",
247 "Basic realm=\"test realm\"");
248 return http_response
.Pass();
255 // PasswordManagerBrowserTest -------------------------------------------------
257 class PasswordManagerBrowserTest
: public InProcessBrowserTest
{
259 PasswordManagerBrowserTest() {}
260 ~PasswordManagerBrowserTest() override
{}
262 // InProcessBrowserTest:
263 void SetUpOnMainThread() override
{
264 // Use TestPasswordStore to remove a possible race. Normally the
265 // PasswordStore does its database manipulation on the DB thread, which
266 // creates a possible race during navigation. Specifically the
267 // PasswordManager will ignore any forms in a page if the load from the
268 // PasswordStore has not completed.
269 PasswordStoreFactory::GetInstance()->SetTestingFactory(
270 browser()->profile(), TestPasswordStoreService::Build
);
271 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
272 ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
273 password_manager::switches::kEnableAutomaticPasswordSaving
));
276 void TearDownOnMainThread() override
{
277 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
281 content::WebContents
* WebContents() {
282 return browser()->tab_strip_model()->GetActiveWebContents();
285 content::RenderViewHost
* RenderViewHost() {
286 return WebContents()->GetRenderViewHost();
289 // Wrapper around ui_test_utils::NavigateToURL that waits until
290 // DidFinishLoad() fires. Normally this function returns after
291 // DidStopLoading(), which caused flakiness as the NavigationObserver
292 // would sometimes see the DidFinishLoad event from a previous navigation and
293 // return immediately.
294 void NavigateToFile(const std::string
& path
) {
295 NavigationObserver
observer(WebContents());
296 GURL url
= embedded_test_server()->GetURL(path
);
297 ui_test_utils::NavigateToURL(browser(), url
);
301 // Waits until the "value" attribute of the HTML element with |element_id| is
302 // equal to |expected_value|. If the current value is not as expected, this
303 // waits until the "change" event is fired for the element. This also
304 // guarantees that once the real value matches the expected, the JavaScript
305 // event loop is spun to allow all other possible events to take place.
306 void WaitForElementValue(const std::string
& element_id
,
307 const std::string
& expected_value
);
308 // Checks that the current "value" attribute of the HTML element with
309 // |element_id| is equal to |expected_value|.
310 void CheckElementValue(const std::string
& element_id
,
311 const std::string
& expected_value
);
314 DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest
);
317 void PasswordManagerBrowserTest::WaitForElementValue(
318 const std::string
& element_id
,
319 const std::string
& expected_value
) {
320 enum ReturnCodes
{ // Possible results of the JavaScript code.
322 RETURN_CODE_NO_ELEMENT
,
323 RETURN_CODE_WRONG_VALUE
,
326 const std::string value_check_function
= base::StringPrintf(
327 "function valueCheck() {"
328 " var element = document.getElementById('%s');"
329 " return element && element.value == '%s';"
332 expected_value
.c_str());
333 const std::string script
=
334 value_check_function
+
336 "if (valueCheck()) {"
337 " /* Spin the event loop with setTimeout. */"
338 " setTimeout(window.domAutomationController.send(%d), 0);"
340 " var element = document.getElementById('%s');"
342 " window.domAutomationController.send(%d);"
343 " element.onchange = function() {"
344 " if (valueCheck()) {"
345 " /* Spin the event loop with setTimeout. */"
346 " setTimeout(window.domAutomationController.send(%d), 0);"
348 " window.domAutomationController.send(%d);"
354 RETURN_CODE_NO_ELEMENT
,
356 RETURN_CODE_WRONG_VALUE
);
357 int return_value
= RETURN_CODE_INVALID
;
358 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
359 RenderViewHost(), script
, &return_value
));
360 EXPECT_EQ(RETURN_CODE_OK
, return_value
)
361 << "element_id = " << element_id
362 << ", expected_value = " << expected_value
;
365 void PasswordManagerBrowserTest::CheckElementValue(
366 const std::string
& element_id
,
367 const std::string
& expected_value
) {
368 const std::string value_check_script
= base::StringPrintf(
369 "var element = document.getElementById('%s');"
370 "window.domAutomationController.send(element && element.value == '%s');",
372 expected_value
.c_str());
373 bool return_value
= false;
374 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
375 RenderViewHost(), value_check_script
, &return_value
));
376 EXPECT_TRUE(return_value
) << "element_id = " << element_id
377 << ", expected_value = " << expected_value
;
380 // Actual tests ---------------------------------------------------------------
381 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
382 PromptForNormalSubmit
) {
383 NavigateToFile("/password/password_form.html");
385 // Fill a form and submit through a <input type="submit"> button. Nothing
387 NavigationObserver
observer(WebContents());
388 scoped_ptr
<PromptObserver
> prompt_observer(
389 PromptObserver::Create(WebContents()));
390 std::string fill_and_submit
=
391 "document.getElementById('username_field').value = 'temp';"
392 "document.getElementById('password_field').value = 'random';"
393 "document.getElementById('input_submit_button').click()";
394 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
396 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
399 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
400 PromptForSubmitWithInPageNavigation
) {
401 NavigateToFile("/password/password_navigate_before_submit.html");
403 // Fill a form and submit through a <input type="submit"> button. Nothing
404 // special. The form does an in-page navigation before submitting.
405 NavigationObserver
observer(WebContents());
406 scoped_ptr
<PromptObserver
> prompt_observer(
407 PromptObserver::Create(WebContents()));
408 std::string fill_and_submit
=
409 "document.getElementById('username_field').value = 'temp';"
410 "document.getElementById('password_field').value = 'random';"
411 "document.getElementById('input_submit_button').click()";
412 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
414 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
417 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
418 LoginSuccessWithUnrelatedForm
) {
419 // Log in, see a form on the landing page. That form is not related to the
420 // login form (=has a different action), so we should offer saving the
422 NavigateToFile("/password/password_form.html");
424 NavigationObserver
observer(WebContents());
425 scoped_ptr
<PromptObserver
> prompt_observer(
426 PromptObserver::Create(WebContents()));
427 std::string fill_and_submit
=
428 "document.getElementById('username_unrelated').value = 'temp';"
429 "document.getElementById('password_unrelated').value = 'random';"
430 "document.getElementById('submit_unrelated').click()";
431 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
433 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
436 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, LoginFailed
) {
437 // Log in, see a form on the landing page. That form is not related to the
438 // login form (=has a different action), so we should offer saving the
440 NavigateToFile("/password/password_form.html");
442 NavigationObserver
observer(WebContents());
443 scoped_ptr
<PromptObserver
> prompt_observer(
444 PromptObserver::Create(WebContents()));
445 std::string fill_and_submit
=
446 "document.getElementById('username_failed').value = 'temp';"
447 "document.getElementById('password_failed').value = 'random';"
448 "document.getElementById('submit_failed').click()";
449 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
451 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
454 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, Redirects
) {
455 NavigateToFile("/password/password_form.html");
457 // Fill a form and submit through a <input type="submit"> button. The form
458 // points to a redirection page.
459 NavigationObserver
observer(WebContents());
460 scoped_ptr
<PromptObserver
> prompt_observer(
461 PromptObserver::Create(WebContents()));
462 std::string fill_and_submit
=
463 "document.getElementById('username_redirect').value = 'temp';"
464 "document.getElementById('password_redirect').value = 'random';"
465 "document.getElementById('submit_redirect').click()";
466 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
468 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
470 // The redirection page now redirects via Javascript. We check that the
472 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
473 "window.location.href = 'done.html';"));
475 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
478 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
479 PromptForSubmitUsingJavaScript
) {
480 NavigateToFile("/password/password_form.html");
482 // Fill a form and submit using <button> that calls submit() on the form.
483 // This should work regardless of the type of element, as long as submit() is
485 NavigationObserver
observer(WebContents());
486 scoped_ptr
<PromptObserver
> prompt_observer(
487 PromptObserver::Create(WebContents()));
488 std::string fill_and_submit
=
489 "document.getElementById('username_field').value = 'temp';"
490 "document.getElementById('password_field').value = 'random';"
491 "document.getElementById('submit_button').click()";
492 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
494 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
497 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
499 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
500 DISABLED_PromptForDynamicForm
) {
501 NavigateToFile("/password/dynamic_password_form.html");
503 // Fill the dynamic password form and submit.
504 NavigationObserver
observer(WebContents());
505 scoped_ptr
<PromptObserver
> prompt_observer(
506 PromptObserver::Create(WebContents()));
507 std::string fill_and_submit
=
508 "document.getElementById('create_form_button').click();"
509 "window.setTimeout(function() {"
510 " document.dynamic_form.username.value = 'tempro';"
511 " document.dynamic_form.password.value = 'random';"
512 " document.dynamic_form.submit();"
514 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
516 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
519 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, NoPromptForNavigation
) {
520 NavigateToFile("/password/password_form.html");
522 // Don't fill the password form, just navigate away. Shouldn't prompt.
523 NavigationObserver
observer(WebContents());
524 scoped_ptr
<PromptObserver
> prompt_observer(
525 PromptObserver::Create(WebContents()));
526 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
527 "window.location.href = 'done.html';"));
529 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
532 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
533 NoPromptForSubFrameNavigation
) {
534 NavigateToFile("/password/multi_frames.html");
536 // If you are filling out a password form in one frame and a different frame
537 // navigates, this should not trigger the infobar.
538 NavigationObserver
observer(WebContents());
539 scoped_ptr
<PromptObserver
> prompt_observer(
540 PromptObserver::Create(WebContents()));
541 observer
.SetPathToWaitFor("/password/done.html");
543 "var first_frame = document.getElementById('first_frame');"
544 "var frame_doc = first_frame.contentDocument;"
545 "frame_doc.getElementById('username_field').value = 'temp';"
546 "frame_doc.getElementById('password_field').value = 'random';";
547 std::string navigate_frame
=
548 "var second_iframe = document.getElementById('second_frame');"
549 "second_iframe.contentWindow.location.href = 'done.html';";
551 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill
));
552 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame
));
554 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
557 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
558 PromptAfterSubmitWithSubFrameNavigation
) {
559 NavigateToFile("/password/multi_frames.html");
561 // Make sure that we prompt to save password even if a sub-frame navigation
563 NavigationObserver
observer(WebContents());
564 scoped_ptr
<PromptObserver
> prompt_observer(
565 PromptObserver::Create(WebContents()));
566 observer
.SetPathToWaitFor("/password/done.html");
567 std::string navigate_frame
=
568 "var second_iframe = document.getElementById('second_frame');"
569 "second_iframe.contentWindow.location.href = 'other.html';";
570 std::string fill_and_submit
=
571 "var first_frame = document.getElementById('first_frame');"
572 "var frame_doc = first_frame.contentDocument;"
573 "frame_doc.getElementById('username_field').value = 'temp';"
574 "frame_doc.getElementById('password_field').value = 'random';"
575 "frame_doc.getElementById('input_submit_button').click();";
577 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame
));
578 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
580 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
583 IN_PROC_BROWSER_TEST_F(
584 PasswordManagerBrowserTest
,
585 NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage
) {
586 NavigateToFile("/password/multi_frames.html");
588 // Make sure that we don't prompt to save the password for a failed login
589 // from the main frame with multiple frames in the same page.
590 NavigationObserver
observer(WebContents());
591 scoped_ptr
<PromptObserver
> prompt_observer(
592 PromptObserver::Create(WebContents()));
593 std::string fill_and_submit
=
594 "document.getElementById('username_failed').value = 'temp';"
595 "document.getElementById('password_failed').value = 'random';"
596 "document.getElementById('submit_failed').click();";
598 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
600 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
603 IN_PROC_BROWSER_TEST_F(
604 PasswordManagerBrowserTest
,
605 NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage
) {
606 NavigateToFile("/password/multi_frames.html");
608 // Make sure that we don't prompt to save the password for a failed login
609 // from a sub-frame with multiple frames in the same page.
610 NavigationObserver
observer(WebContents());
611 scoped_ptr
<PromptObserver
> prompt_observer(
612 PromptObserver::Create(WebContents()));
613 std::string fill_and_submit
=
614 "var first_frame = document.getElementById('first_frame');"
615 "var frame_doc = first_frame.contentDocument;"
616 "frame_doc.getElementById('username_failed').value = 'temp';"
617 "frame_doc.getElementById('password_failed').value = 'random';"
618 "frame_doc.getElementById('submit_failed').click();"
619 "window.parent.location.href = 'multi_frames.html';";
621 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
623 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
626 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, PromptForXHRSubmit
) {
627 #if defined(OS_WIN) && defined(USE_ASH)
628 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
629 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests
))
632 NavigateToFile("/password/password_xhr_submit.html");
634 // Verify that we show the save password prompt if a form returns false
635 // in its onsubmit handler but instead logs in/navigates via XHR.
636 // Note that calling 'submit()' on a form with javascript doesn't call
637 // the onsubmit handler, so we click the submit button instead.
638 NavigationObserver
observer(WebContents());
639 scoped_ptr
<PromptObserver
> prompt_observer(
640 PromptObserver::Create(WebContents()));
641 std::string fill_and_submit
=
642 "document.getElementById('username_field').value = 'temp';"
643 "document.getElementById('password_field').value = 'random';"
644 "document.getElementById('submit_button').click()";
645 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
647 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
650 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
651 PromptForXHRWithoutOnSubmit
) {
652 NavigateToFile("/password/password_xhr_submit.html");
654 // Verify that if XHR navigation occurs and the form is properly filled out,
655 // we try and save the password even though onsubmit hasn't been called.
656 NavigationObserver
observer(WebContents());
657 scoped_ptr
<PromptObserver
> prompt_observer(
658 PromptObserver::Create(WebContents()));
659 std::string fill_and_navigate
=
660 "document.getElementById('username_field').value = 'temp';"
661 "document.getElementById('password_field').value = 'random';"
663 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate
));
665 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
668 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
669 PromptForXHRWithNewPasswordsWithoutOnSubmit
) {
670 NavigateToFile("/password/password_xhr_submit.html");
672 // Verify that if XHR navigation occurs and the form is properly filled out,
673 // we try and save the password even though onsubmit hasn't been called.
674 // Specifically verify that the password form saving new passwords is treated
675 // the same as a login form.
676 NavigationObserver
observer(WebContents());
677 scoped_ptr
<PromptObserver
> prompt_observer(
678 PromptObserver::Create(WebContents()));
679 std::string fill_and_navigate
=
680 "document.getElementById('signup_username_field').value = 'temp';"
681 "document.getElementById('signup_password_field').value = 'random';"
682 "document.getElementById('confirmation_password_field').value = 'random';"
684 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate
));
686 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
689 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, NoPromptIfLinkClicked
) {
690 NavigateToFile("/password/password_form.html");
692 // Verify that if the user takes a direct action to leave the page, we don't
693 // prompt to save the password even if the form is already filled out.
694 NavigationObserver
observer(WebContents());
695 scoped_ptr
<PromptObserver
> prompt_observer(
696 PromptObserver::Create(WebContents()));
697 std::string fill_and_click_link
=
698 "document.getElementById('username_field').value = 'temp';"
699 "document.getElementById('password_field').value = 'random';"
700 "document.getElementById('link').click();";
701 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link
));
703 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
706 // TODO(jam): http://crbug.com/350550
708 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
709 VerifyPasswordGenerationUpload
) {
710 // Prevent Autofill requests from actually going over the wire.
711 net::TestURLFetcherFactory factory
;
712 // Disable Autofill requesting access to AddressBook data. This causes
713 // the test to hang on Mac.
714 autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
716 // Visit a signup form.
717 NavigateToFile("/password/signup_form.html");
719 // Enter a password and save it.
720 NavigationObserver
first_observer(WebContents());
721 scoped_ptr
<PromptObserver
> prompt_observer(
722 PromptObserver::Create(WebContents()));
723 std::string fill_and_submit
=
724 "document.getElementById('other_info').value = 'stuff';"
725 "document.getElementById('username_field').value = 'my_username';"
726 "document.getElementById('password_field').value = 'password';"
727 "document.getElementById('input_submit_button').click()";
728 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
730 first_observer
.Wait();
731 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
732 prompt_observer
->Accept();
734 // Now navigate to a login form that has similar HTML markup.
735 NavigateToFile("/password/password_form.html");
737 // Simulate a user click to force an autofill of the form's DOM value, not
738 // just the suggested value.
739 content::SimulateMouseClick(
740 WebContents(), 0, blink::WebMouseEvent::ButtonLeft
);
742 // The form should be filled with the previously submitted username.
743 std::string get_username
=
744 "window.domAutomationController.send("
745 "document.getElementById('username_field').value);";
746 std::string actual_username
;
747 ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
750 ASSERT_EQ("my_username", actual_username
);
752 // Submit the form and verify that there is no infobar (as the password
753 // has already been saved).
754 NavigationObserver
second_observer(WebContents());
755 scoped_ptr
<PromptObserver
> second_prompt_observer(
756 PromptObserver::Create(WebContents()));
757 std::string submit_form
=
758 "document.getElementById('input_submit_button').click()";
759 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form
));
760 second_observer
.Wait();
761 EXPECT_FALSE(second_prompt_observer
->IsShowingPrompt());
763 // Verify that we sent two pings to Autofill. One vote for of PASSWORD for
764 // the current form, and one vote for ACCOUNT_CREATION_PASSWORD on the
765 // original form since it has more than 2 text input fields and was used for
766 // the first time on a different form.
767 base::HistogramBase
* upload_histogram
=
768 base::StatisticsRecorder::FindHistogram(
769 "PasswordGeneration.UploadStarted");
770 ASSERT_TRUE(upload_histogram
);
771 scoped_ptr
<base::HistogramSamples
> snapshot
=
772 upload_histogram
->SnapshotSamples();
773 EXPECT_EQ(0, snapshot
->GetCount(0 /* failure */));
774 EXPECT_EQ(2, snapshot
->GetCount(1 /* success */));
778 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, PromptForSubmitFromIframe
) {
779 NavigateToFile("/password/password_submit_from_iframe.html");
781 // Submit a form in an iframe, then cause the whole page to navigate without a
782 // user gesture. We expect the save password prompt to be shown here, because
783 // some pages use such iframes for login forms.
784 NavigationObserver
observer(WebContents());
785 scoped_ptr
<PromptObserver
> prompt_observer(
786 PromptObserver::Create(WebContents()));
787 std::string fill_and_submit
=
788 "var iframe = document.getElementById('test_iframe');"
789 "var iframe_doc = iframe.contentDocument;"
790 "iframe_doc.getElementById('username_field').value = 'temp';"
791 "iframe_doc.getElementById('password_field').value = 'random';"
792 "iframe_doc.getElementById('submit_button').click()";
794 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
796 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
799 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
800 PromptForInputElementWithoutName
) {
801 // Check that the prompt is shown for forms where input elements lack the
802 // "name" attribute but the "id" is present.
803 NavigateToFile("/password/password_form.html");
805 NavigationObserver
observer(WebContents());
806 scoped_ptr
<PromptObserver
> prompt_observer(
807 PromptObserver::Create(WebContents()));
808 std::string fill_and_submit
=
809 "document.getElementById('username_field_no_name').value = 'temp';"
810 "document.getElementById('password_field_no_name').value = 'random';"
811 "document.getElementById('input_submit_button_no_name').click()";
812 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
814 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
817 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
818 PromptForInputElementWithoutId
) {
819 // Check that the prompt is shown for forms where input elements lack the
820 // "id" attribute but the "name" attribute is present.
821 NavigateToFile("/password/password_form.html");
823 NavigationObserver
observer(WebContents());
824 scoped_ptr
<PromptObserver
> prompt_observer(
825 PromptObserver::Create(WebContents()));
826 std::string fill_and_submit
=
827 "document.getElementsByName('username_field_no_id')[0].value = 'temp';"
828 "document.getElementsByName('password_field_no_id')[0].value = 'random';"
829 "document.getElementsByName('input_submit_button_no_id')[0].click()";
830 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
832 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
835 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
836 NoPromptForInputElementWithoutIdAndName
) {
837 // Check that no prompt is shown for forms where the input fields lack both
838 // the "id" and the "name" attributes.
839 NavigateToFile("/password/password_form.html");
841 NavigationObserver
observer(WebContents());
842 scoped_ptr
<PromptObserver
> prompt_observer(
843 PromptObserver::Create(WebContents()));
844 std::string fill_and_submit
=
845 "var form = document.getElementById('testform_elements_no_id_no_name');"
846 "var username = form.children[0];"
847 "username.value = 'temp';"
848 "var password = form.children[1];"
849 "password.value = 'random';"
850 "form.children[2].click()"; // form.children[2] is the submit button.
851 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
853 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
856 // Test for checking that no prompt is shown for URLs with file: scheme.
857 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
858 NoPromptForFileSchemeURLs
) {
859 GURL url
= GetFileURL("password_form.html");
860 ui_test_utils::NavigateToURL(browser(), url
);
862 NavigationObserver
observer(WebContents());
863 scoped_ptr
<PromptObserver
> prompt_observer(
864 PromptObserver::Create(WebContents()));
865 std::string fill_and_submit
=
866 "document.getElementById('username_field').value = 'temp';"
867 "document.getElementById('password_field').value = 'random';"
868 "document.getElementById('input_submit_button').click();";
869 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
871 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
874 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, DeleteFrameBeforeSubmit
) {
875 NavigateToFile("/password/multi_frames.html");
877 NavigationObserver
observer(WebContents());
878 // Make sure we save some password info from an iframe and then destroy it.
879 std::string save_and_remove
=
880 "var first_frame = document.getElementById('first_frame');"
881 "var frame_doc = first_frame.contentDocument;"
882 "frame_doc.getElementById('username_field').value = 'temp';"
883 "frame_doc.getElementById('password_field').value = 'random';"
884 "frame_doc.getElementById('input_submit_button').click();"
885 "first_frame.parentNode.removeChild(first_frame);";
886 // Submit from the main frame, but without navigating through the onsubmit
888 std::string navigate_frame
=
889 "document.getElementById('username_field').value = 'temp';"
890 "document.getElementById('password_field').value = 'random';"
891 "document.getElementById('input_submit_button').click();"
892 "window.location.href = 'done.html';";
894 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), save_and_remove
));
895 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame
));
897 // The only thing we check here is that there is no use-after-free reported.
900 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, PasswordValueAccessible
) {
901 NavigateToFile("/password/form_and_link.html");
903 // Click on a link to open a new tab, then switch back to the first one.
904 EXPECT_EQ(1, browser()->tab_strip_model()->count());
906 "document.getElementById('testlink').click();";
907 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), click
));
908 EXPECT_EQ(2, browser()->tab_strip_model()->count());
909 browser()->tab_strip_model()->ActivateTabAt(0, false);
911 // Fill in the credentials, and make sure they are saved.
912 NavigationObserver
form_submit_observer(WebContents());
913 scoped_ptr
<PromptObserver
> prompt_observer(
914 PromptObserver::Create(WebContents()));
915 std::string fill_and_submit
=
916 "document.getElementById('username_field').value = 'temp';"
917 "document.getElementById('password_field').value = 'random';"
918 "document.getElementById('input_submit_button').click();";
919 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
920 form_submit_observer
.Wait();
921 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
922 prompt_observer
->Accept();
924 // Reload the original page to have the saved credentials autofilled.
925 NavigationObserver
reload_observer(WebContents());
926 NavigateToFile("/password/form_and_link.html");
927 reload_observer
.Wait();
929 // Wait until the username is filled, to make sure autofill kicked in.
930 WaitForElementValue("username_field", "temp");
931 // Now check that the password is not accessible yet.
932 CheckElementValue("password_field", "");
933 // Let the user interact with the page.
934 content::SimulateMouseClickAt(
935 WebContents(), 0, blink::WebMouseEvent::ButtonLeft
, gfx::Point(1, 1));
936 // Wait until that interaction causes the password value to be revealed.
937 WaitForElementValue("password_field", "random");
938 // And check that after the side-effects of the interaction took place, the
939 // username value stays the same.
940 CheckElementValue("username_field", "temp");
943 // The following test is limited to Aura, because
944 // RenderWidgetHostViewGuest::ProcessAckedTouchEvent is, and
945 // ProcessAckedTouchEvent is what triggers the translation of touch events to
947 #if defined(USE_AURA)
948 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
949 PasswordValueAccessibleOnSubmit
) {
950 NavigateToFile("/password/form_and_link.html");
952 // Fill in the credentials, and make sure they are saved.
953 NavigationObserver
form_submit_observer(WebContents());
954 scoped_ptr
<PromptObserver
> prompt_observer(
955 PromptObserver::Create(WebContents()));
956 std::string fill_and_submit
=
957 "document.getElementById('username_field').value = 'temp';"
958 "document.getElementById('password_field').value = 'random_secret';"
959 "document.getElementById('input_submit_button').click();";
960 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
961 form_submit_observer
.Wait();
962 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
963 prompt_observer
->Accept();
965 // Reload the original page to have the saved credentials autofilled.
966 NavigationObserver
reload_observer(WebContents());
967 NavigateToFile("/password/form_and_link.html");
968 reload_observer
.Wait();
970 NavigationObserver
submit_observer(WebContents());
971 // Submit the form via a tap on the submit button. The button is placed at 0,
972 // 100, and has height 300 and width 700.
973 content::SimulateTapAt(WebContents(), gfx::Point(350, 250));
974 submit_observer
.Wait();
975 std::string query
= WebContents()->GetURL().query();
976 EXPECT_NE(std::string::npos
, query
.find("random_secret")) << query
;
980 // Test fix for crbug.com/338650.
981 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
982 DontPromptForPasswordFormWithDefaultValue
) {
983 NavigateToFile("/password/password_form_with_default_value.html");
985 // Don't prompt if we navigate away even if there is a password value since
986 // it's not coming from the user.
987 NavigationObserver
observer(WebContents());
988 scoped_ptr
<PromptObserver
> prompt_observer(
989 PromptObserver::Create(WebContents()));
990 NavigateToFile("/password/done.html");
992 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
995 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
996 PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet
) {
997 NavigateToFile("/password/password_form.html");
999 // Fill a form and submit through a <input type="submit"> button.
1000 NavigationObserver
observer(WebContents());
1001 scoped_ptr
<PromptObserver
> prompt_observer(
1002 PromptObserver::Create(WebContents()));
1003 std::string fill_and_submit
=
1004 "document.getElementById('username_field').value = 'temp';"
1005 "document.getElementById('password_field').value = 'random';"
1006 "document.getElementById('input_submit_button').click()";
1007 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
1009 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1012 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
1013 DontPromptWhenEnableAutomaticPasswordSavingSwitchIsSet
) {
1014 password_manager::TestPasswordStore
* password_store
=
1015 static_cast<password_manager::TestPasswordStore
*>(
1016 PasswordStoreFactory::GetForProfile(browser()->profile(),
1017 Profile::IMPLICIT_ACCESS
).get());
1019 EXPECT_TRUE(password_store
->IsEmpty());
1021 NavigateToFile("/password/password_form.html");
1023 // Add the enable-automatic-password-saving switch.
1024 CommandLine::ForCurrentProcess()->AppendSwitch(
1025 password_manager::switches::kEnableAutomaticPasswordSaving
);
1027 // Fill a form and submit through a <input type="submit"> button.
1028 NavigationObserver
observer(WebContents());
1029 scoped_ptr
<PromptObserver
> prompt_observer(
1030 PromptObserver::Create(WebContents()));
1031 // Make sure that the only passwords saved are the auto-saved ones.
1032 std::string fill_and_submit
=
1033 "document.getElementById('username_field').value = 'temp';"
1034 "document.getElementById('password_field').value = 'random';"
1035 "document.getElementById('input_submit_button').click()";
1036 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit
));
1038 if (chrome::VersionInfo::GetChannel() ==
1039 chrome::VersionInfo::CHANNEL_UNKNOWN
) {
1040 // Passwords getting auto-saved, no prompt.
1041 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
1042 EXPECT_FALSE(password_store
->IsEmpty());
1044 // Prompt shown, and no passwords saved automatically.
1045 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1046 EXPECT_TRUE(password_store
->IsEmpty());
1050 // Test fix for crbug.com/368690.
1051 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, NoPromptWhenReloading
) {
1052 NavigateToFile("/password/password_form.html");
1055 "document.getElementById('username_redirect').value = 'temp';"
1056 "document.getElementById('password_redirect').value = 'random';";
1057 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill
));
1059 NavigationObserver
observer(WebContents());
1060 scoped_ptr
<PromptObserver
> prompt_observer(
1061 PromptObserver::Create(WebContents()));
1062 GURL url
= embedded_test_server()->GetURL("/password/password_form.html");
1063 chrome::NavigateParams
params(browser(), url
,
1064 ui::PAGE_TRANSITION_RELOAD
);
1065 ui_test_utils::NavigateToURL(¶ms
);
1067 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
1070 // Test that if a form gets dynamically added between the form parsing and
1071 // rendering, and while the main frame still loads, it still is registered, and
1072 // thus saving passwords from it works.
1073 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
1074 FormsAddedBetweenParsingAndRendering
) {
1075 NavigateToFile("/password/between_parsing_and_rendering.html");
1077 NavigationObserver
observer(WebContents());
1078 scoped_ptr
<PromptObserver
> prompt_observer(
1079 PromptObserver::Create(WebContents()));
1080 std::string submit
=
1081 "document.getElementById('username').value = 'temp';"
1082 "document.getElementById('password').value = 'random';"
1083 "document.getElementById('submit-button').click();";
1084 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit
));
1087 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1090 // Test that if there was no previous page load then the PasswordManagerDriver
1091 // does not think that there were SSL errors on the current page. The test opens
1092 // a new tab with a URL for which the embedded test server issues a basic auth
1094 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
, NoLastLoadGoodLastLoad
) {
1095 // Teach the embedded server to handle requests by issuing the basic auth
1097 embedded_test_server()->RegisterRequestHandler(
1098 base::Bind(&HandleTestAuthRequest
));
1100 LoginPromptBrowserTestObserver login_observer
;
1101 // We need to register to all sources, because the navigation observer we are
1102 // interested in is for a new tab to be opened, and thus does not exist yet.
1103 login_observer
.Register(content::NotificationService::AllSources());
1105 password_manager::TestPasswordStore
* password_store
=
1106 static_cast<password_manager::TestPasswordStore
*>(
1107 PasswordStoreFactory::GetForProfile(browser()->profile(),
1108 Profile::IMPLICIT_ACCESS
).get());
1109 EXPECT_TRUE(password_store
->IsEmpty());
1111 // Navigate to a page requiring HTTP auth. Wait for the tab to get the correct
1112 // WebContents, but don't wait for navigation, which only finishes after
1114 ui_test_utils::NavigateToURLWithDisposition(
1116 embedded_test_server()->GetURL("/basic_auth"),
1118 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
1120 content::NavigationController
* nav_controller
=
1121 &WebContents()->GetController();
1122 NavigationObserver
nav_observer(WebContents());
1123 scoped_ptr
<PromptObserver
> prompt_observer(
1124 PromptObserver::Create(WebContents()));
1125 WindowedAuthNeededObserver
auth_needed_observer(nav_controller
);
1126 auth_needed_observer
.Wait();
1128 WindowedAuthSuppliedObserver
auth_supplied_observer(nav_controller
);
1129 // Offer valid credentials on the auth challenge.
1130 ASSERT_EQ(1u, login_observer
.handlers().size());
1131 LoginHandler
* handler
= *login_observer
.handlers().begin();
1132 ASSERT_TRUE(handler
);
1133 // Any username/password will work.
1134 handler
->SetAuth(base::UTF8ToUTF16("user"), base::UTF8ToUTF16("pwd"));
1135 auth_supplied_observer
.Wait();
1137 // The password manager should be working correctly.
1138 nav_observer
.Wait();
1139 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1140 prompt_observer
->Accept();
1142 // Spin the message loop to make sure the password store had a chance to save
1144 base::RunLoop run_loop
;
1145 run_loop
.RunUntilIdle();
1146 EXPECT_FALSE(password_store
->IsEmpty());
1149 // In some situations, multiple PasswordFormManager instances from
1150 // PasswordManager::pending_login_managers_ would match (via DoesManage) a form
1151 // to be provisionally saved. One of them might be a complete match, the other
1152 // all-but-action match. Normally, the former should be preferred, but if the
1153 // former has not finished matching, and the latter has, the latter should be
1154 // used (otherwise we'd give up even though we could have saved the password).
1155 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
1156 PreferPasswordFormManagerWhichFinishedMatching
) {
1157 NavigateToFile("/password/create_form_copy_on_submit.html");
1159 NavigationObserver
observer(WebContents());
1160 scoped_ptr
<PromptObserver
> prompt_observer(
1161 PromptObserver::Create(WebContents()));
1162 std::string submit
=
1163 "document.getElementById('username').value = 'overwrite_me';"
1164 "document.getElementById('password').value = 'random';"
1165 "document.getElementById('non-form-button').click();";
1166 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit
));
1169 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1172 // Test that if login fails and content server pushes a different login form
1173 // with action URL having different schemes. Heuristic shall be able
1174 // identify such cases and *shall not* prompt to save incorrect password.
1175 IN_PROC_BROWSER_TEST_F(
1176 PasswordManagerBrowserTest
,
1177 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpToHttps
) {
1179 "/password/separate_login_form_with_onload_submit_script.html";
1180 GURL
http_url(embedded_test_server()->GetURL(path
));
1181 ASSERT_TRUE(http_url
.SchemeIs(url::kHttpScheme
));
1183 NavigationObserver
observer(WebContents());
1184 scoped_ptr
<PromptObserver
> prompt_observer(
1185 PromptObserver::Create(WebContents()));
1186 ui_test_utils::NavigateToURL(browser(), http_url
);
1188 observer
.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1191 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
1194 IN_PROC_BROWSER_TEST_F(
1195 PasswordManagerBrowserTest
,
1196 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpsToHttp
) {
1197 CommandLine::ForCurrentProcess()->AppendSwitch(
1198 switches::kAllowRunningInsecureContent
);
1199 CommandLine::ForCurrentProcess()->AppendSwitch(
1200 switches::kIgnoreCertificateErrors
);
1201 const base::FilePath::CharType kDocRoot
[] =
1202 FILE_PATH_LITERAL("chrome/test/data");
1203 net::SpawnedTestServer
https_test_server(
1204 net::SpawnedTestServer::TYPE_HTTPS
,
1205 net::SpawnedTestServer::SSLOptions(
1206 net::SpawnedTestServer::SSLOptions::CERT_OK
),
1207 base::FilePath(kDocRoot
));
1208 ASSERT_TRUE(https_test_server
.Start());
1210 // This test case cannot inject the scripts via content::ExecuteScript() in
1211 // files served through HTTPS. Therefore the scripts are made part of the HTML
1212 // site and executed on load.
1214 "password/separate_login_form_with_onload_submit_script.html";
1215 GURL
https_url(https_test_server
.GetURL(path
));
1216 ASSERT_TRUE(https_url
.SchemeIs(url::kHttpsScheme
));
1218 NavigationObserver
observer(WebContents());
1219 scoped_ptr
<PromptObserver
> prompt_observer(
1220 PromptObserver::Create(WebContents()));
1221 ui_test_utils::NavigateToURL(browser(), https_url
);
1223 observer
.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1226 EXPECT_FALSE(prompt_observer
->IsShowingPrompt());
1229 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
1230 PromptWhenPasswordFormWithoutUsernameFieldSubmitted
) {
1231 password_manager::TestPasswordStore
* password_store
=
1232 static_cast<password_manager::TestPasswordStore
*>(
1233 PasswordStoreFactory::GetForProfile(browser()->profile(),
1234 Profile::IMPLICIT_ACCESS
).get());
1236 EXPECT_TRUE(password_store
->IsEmpty());
1238 NavigateToFile("/password/form_with_only_password_field.html");
1240 NavigationObserver
observer(WebContents());
1241 scoped_ptr
<PromptObserver
> prompt_observer(
1242 PromptObserver::Create(WebContents()));
1243 std::string submit
=
1244 "document.getElementById('password').value = 'password';"
1245 "document.getElementById('submit-button').click();";
1246 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit
));
1249 EXPECT_TRUE(prompt_observer
->IsShowingPrompt());
1250 prompt_observer
->Accept();
1252 // Spin the message loop to make sure the password store had a chance to save
1254 base::RunLoop run_loop
;
1255 run_loop
.RunUntilIdle();
1256 EXPECT_FALSE(password_store
->IsEmpty());
1259 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest
,
1260 AutofillSuggetionsForPasswordFormWithoutUsernameField
) {
1261 password_manager::TestPasswordStore
* password_store
=
1262 static_cast<password_manager::TestPasswordStore
*>(
1263 PasswordStoreFactory::GetForProfile(browser()->profile(),
1264 Profile::IMPLICIT_ACCESS
).get());
1266 EXPECT_TRUE(password_store
->IsEmpty());
1268 // Password form without username-field.
1269 NavigateToFile("/password/form_with_only_password_field.html");
1271 NavigationObserver
observer(WebContents());
1272 scoped_ptr
<PromptObserver
> prompt_observer(
1273 PromptObserver::Create(WebContents()));
1274 std::string submit
=
1275 "document.getElementById('password').value = 'mypassword';"
1276 "document.getElementById('submit-button').click();";
1277 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit
));
1280 prompt_observer
->Accept();
1282 // Spin the message loop to make sure the password store had a chance to save
1284 base::RunLoop run_loop
;
1285 run_loop
.RunUntilIdle();
1286 EXPECT_FALSE(password_store
->IsEmpty());
1288 // Now, navigate to same html password form and verify whether password is
1290 NavigateToFile("/password/form_with_only_password_field.html");
1292 // Let the user interact with the page, so that DOM gets modification events,
1293 // needed for autofilling fields.
1294 content::SimulateMouseClickAt(
1295 WebContents(), 0, blink::WebMouseEvent::ButtonLeft
, gfx::Point(1, 1));
1297 // Wait until that interaction causes the password value to be revealed.
1298 WaitForElementValue("password", "mypassword");