1 // Copyright 2015 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 "chrome/browser/password_manager/password_manager_test_base.h"
7 #include "base/command_line.h"
8 #include "base/run_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/infobars/infobar_service.h"
11 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
12 #include "chrome/browser/password_manager/password_store_factory.h"
13 #include "chrome/browser/password_manager/test_password_store_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "components/autofill/core/browser/autofill_test_utils.h"
20 #include "components/infobars/core/confirm_infobar_delegate.h"
21 #include "components/infobars/core/infobar.h"
22 #include "components/infobars/core/infobar_manager.h"
23 #include "components/password_manager/core/common/password_manager_switches.h"
24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/test_utils.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
30 NavigationObserver::NavigationObserver(content::WebContents
* web_contents
)
31 : content::WebContentsObserver(web_contents
),
32 quit_on_entry_committed_(false),
33 message_loop_runner_(new content::MessageLoopRunner
) {
35 NavigationObserver::~NavigationObserver() {
38 void NavigationObserver::DidFinishLoad(
39 content::RenderFrameHost
* render_frame_host
,
40 const GURL
& validated_url
) {
41 render_frame_host_
= render_frame_host
;
42 if (!wait_for_path_
.empty()) {
43 if (validated_url
.path() == wait_for_path_
)
44 message_loop_runner_
->Quit();
45 } else if (!render_frame_host
->GetParent()) {
46 message_loop_runner_
->Quit();
50 void NavigationObserver::NavigationEntryCommitted(
51 const content::LoadCommittedDetails
& load_details
) {
52 if (quit_on_entry_committed_
)
53 message_loop_runner_
->Quit();
56 void NavigationObserver::Wait() {
57 message_loop_runner_
->Run();
60 PromptObserver::PromptObserver() {
62 PromptObserver::~PromptObserver() {
65 void PromptObserver::Accept() const {
66 EXPECT_TRUE(IsShowingPrompt());
70 class InfoBarObserver
: public PromptObserver
,
71 public infobars::InfoBarManager::Observer
{
73 explicit InfoBarObserver(content::WebContents
* web_contents
)
74 : infobar_is_being_shown_(false),
75 infobar_service_(InfoBarService::FromWebContents(web_contents
)) {
76 infobar_service_
->AddObserver(this);
79 ~InfoBarObserver() override
{
81 infobar_service_
->RemoveObserver(this);
86 bool IsShowingPrompt() const override
{ return infobar_is_being_shown_
; }
88 void AcceptImpl() const override
{
89 EXPECT_EQ(1u, infobar_service_
->infobar_count());
90 if (!infobar_service_
->infobar_count())
91 return; // Let the test finish to gather possibly more diagnostics.
93 // ConfirmInfoBarDelegate::Accept returning true means the infobar is
94 // immediately closed. Checking the return value is preferred to testing
95 // IsShowingPrompt() here, for it avoids the delay until the closing
96 // notification is received.
97 EXPECT_TRUE(infobar_service_
->infobar_at(0)
99 ->AsConfirmInfoBarDelegate()
103 // infobars::InfoBarManager::Observer:
104 void OnInfoBarAdded(infobars::InfoBar
* infobar
) override
{
105 infobar_is_being_shown_
= true;
108 void OnInfoBarRemoved(infobars::InfoBar
* infobar
, bool animate
) override
{
109 infobar_is_being_shown_
= false;
112 void OnManagerShuttingDown(infobars::InfoBarManager
* manager
) override
{
113 ASSERT_EQ(infobar_service_
, manager
);
114 infobar_service_
->RemoveObserver(this);
115 infobar_service_
= nullptr;
118 bool infobar_is_being_shown_
;
119 InfoBarService
* infobar_service_
;
121 DISALLOW_COPY_AND_ASSIGN(InfoBarObserver
);
124 class BubbleObserver
: public PromptObserver
{
126 explicit BubbleObserver(content::WebContents
* web_contents
)
128 ManagePasswordsUIController::FromWebContents(web_contents
)) {}
130 ~BubbleObserver() override
{}
134 bool IsShowingPrompt() const override
{
135 return ui_controller_
->PasswordPendingUserDecision();
138 void AcceptImpl() const override
{
139 ui_controller_
->SavePassword();
140 EXPECT_FALSE(IsShowingPrompt());
143 ManagePasswordsUIController
* const ui_controller_
;
145 DISALLOW_COPY_AND_ASSIGN(BubbleObserver
);
148 scoped_ptr
<PromptObserver
> PromptObserver::Create(
149 content::WebContents
* web_contents
) {
150 if (ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled()) {
151 return scoped_ptr
<PromptObserver
>(new BubbleObserver(web_contents
));
153 return scoped_ptr
<PromptObserver
>(new InfoBarObserver(web_contents
));
157 PasswordManagerBrowserTestBase::PasswordManagerBrowserTestBase() {
159 PasswordManagerBrowserTestBase::~PasswordManagerBrowserTestBase() {
162 void PasswordManagerBrowserTestBase::SetUpOnMainThread() {
163 // Use TestPasswordStore to remove a possible race. Normally the
164 // PasswordStore does its database manipulation on the DB thread, which
165 // creates a possible race during navigation. Specifically the
166 // PasswordManager will ignore any forms in a page if the load from the
167 // PasswordStore has not completed.
168 PasswordStoreFactory::GetInstance()->SetTestingFactory(
169 browser()->profile(), TestPasswordStoreService::Build
);
170 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
171 ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
172 password_manager::switches::kEnableAutomaticPasswordSaving
));
175 void PasswordManagerBrowserTestBase::TearDownOnMainThread() {
176 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
179 content::WebContents
* PasswordManagerBrowserTestBase::WebContents() {
180 return browser()->tab_strip_model()->GetActiveWebContents();
183 content::RenderViewHost
* PasswordManagerBrowserTestBase::RenderViewHost() {
184 return WebContents()->GetRenderViewHost();
187 void PasswordManagerBrowserTestBase::NavigateToFile(const std::string
& path
) {
188 NavigationObserver
observer(WebContents());
189 GURL url
= embedded_test_server()->GetURL(path
);
190 ui_test_utils::NavigateToURL(browser(), url
);
194 void PasswordManagerBrowserTestBase::WaitForElementValue(
195 const std::string
& element_id
,
196 const std::string
& expected_value
) {
197 WaitForElementValue("null", element_id
, expected_value
);
200 void PasswordManagerBrowserTestBase::WaitForElementValue(
201 const std::string
& iframe_id
,
202 const std::string
& element_id
,
203 const std::string
& expected_value
) {
204 enum ReturnCodes
{ // Possible results of the JavaScript code.
206 RETURN_CODE_NO_ELEMENT
,
207 RETURN_CODE_WRONG_VALUE
,
210 const std::string value_check_function
= base::StringPrintf(
211 "function valueCheck() {"
213 " var element = document.getElementById("
214 " '%s').contentDocument.getElementById('%s');"
216 " var element = document.getElementById('%s');"
217 " return element && element.value == '%s';"
219 iframe_id
.c_str(), iframe_id
.c_str(), element_id
.c_str(),
220 element_id
.c_str(), expected_value
.c_str());
221 const std::string script
=
222 value_check_function
+
224 "if (valueCheck()) {"
225 " /* Spin the event loop with setTimeout. */"
226 " setTimeout(window.domAutomationController.send(%d), 0);"
229 " var element = document.getElementById("
230 " '%s').contentDocument.getElementById('%s');"
232 " var element = document.getElementById('%s');"
234 " window.domAutomationController.send(%d);"
235 " element.onchange = function() {"
236 " if (valueCheck()) {"
237 " /* Spin the event loop with setTimeout. */"
238 " setTimeout(window.domAutomationController.send(%d), 0);"
240 " window.domAutomationController.send(%d);"
244 RETURN_CODE_OK
, iframe_id
.c_str(), iframe_id
.c_str(),
245 element_id
.c_str(), element_id
.c_str(), RETURN_CODE_NO_ELEMENT
,
246 RETURN_CODE_OK
, RETURN_CODE_WRONG_VALUE
);
247 int return_value
= RETURN_CODE_INVALID
;
248 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(RenderViewHost(), script
,
250 EXPECT_EQ(RETURN_CODE_OK
, return_value
)
251 << "element_id = " << element_id
252 << ", expected_value = " << expected_value
;
255 void PasswordManagerBrowserTestBase::CheckElementValue(
256 const std::string
& element_id
,
257 const std::string
& expected_value
) {
258 CheckElementValue("null", element_id
, expected_value
);
261 void PasswordManagerBrowserTestBase::CheckElementValue(
262 const std::string
& iframe_id
,
263 const std::string
& element_id
,
264 const std::string
& expected_value
) {
265 const std::string value_check_script
= base::StringPrintf(
267 " var element = document.getElementById("
268 " '%s').contentDocument.getElementById('%s');"
270 " var element = document.getElementById('%s');"
271 "window.domAutomationController.send(element && element.value == '%s');",
272 iframe_id
.c_str(), iframe_id
.c_str(), element_id
.c_str(),
273 element_id
.c_str(), expected_value
.c_str());
274 bool return_value
= false;
275 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
276 RenderViewHost(), value_check_script
, &return_value
));
277 EXPECT_TRUE(return_value
) << "element_id = " << element_id
278 << ", expected_value = " << expected_value
;