1 // Copyright (c) 2012 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/ui/webui/options/options_ui_browsertest.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/scoped_observer.h"
9 #include "base/strings/string16.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/signin/signin_manager_factory.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/chrome_pages.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/browser/ui/webui/options/options_ui.h"
17 #include "chrome/browser/ui/webui/uber/uber_ui.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/common/url_constants.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "components/signin/core/browser/signin_manager.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/test_utils.h"
27 #include "grit/generated_resources.h"
28 #include "ui/base/l10n/l10n_util.h"
30 #if !defined(OS_CHROMEOS)
33 #include "base/basictypes.h"
34 #include "base/bind.h"
35 #include "base/callback.h"
36 #include "base/files/file_path.h"
37 #include "base/run_loop.h"
38 #include "chrome/browser/browser_process.h"
39 #include "chrome/browser/profiles/profile.h"
40 #include "chrome/browser/profiles/profile_manager.h"
41 #include "chrome/browser/ui/browser_commands.h"
42 #include "content/public/test/test_navigation_observer.h"
43 #include "ui/base/window_open_disposition.h"
47 using content::MessageLoopRunner
;
53 class SignOutWaiter
: public SigninManagerBase::Observer
{
55 explicit SignOutWaiter(SigninManagerBase
* signin_manager
)
56 : seen_(false), running_(false), scoped_observer_(this) {
57 scoped_observer_
.Add(signin_manager
);
59 virtual ~SignOutWaiter() {}
66 message_loop_runner_
= new MessageLoopRunner
;
67 message_loop_runner_
->Run();
71 virtual void GoogleSignedOut(const std::string
& username
) OVERRIDE
{
76 message_loop_runner_
->Quit();
83 ScopedObserver
<SigninManagerBase
, SignOutWaiter
> scoped_observer_
;
84 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
87 #if !defined(OS_CHROMEOS)
88 void RunClosureWhenProfileInitialized(const base::Closure
& closure
,
90 Profile::CreateStatus status
) {
91 if (status
== Profile::CREATE_STATUS_INITIALIZED
)
96 bool FrameHasSettingsSourceHost(content::RenderFrameHost
* frame
) {
97 return frame
->GetLastCommittedURL().DomainIs(
98 chrome::kChromeUISettingsFrameHost
);
103 OptionsUIBrowserTest::OptionsUIBrowserTest() {
106 void OptionsUIBrowserTest::NavigateToSettings() {
107 NavigateToSettingsSubpage("");
110 void OptionsUIBrowserTest::NavigateToSettingsSubpage(
111 const std::string
& sub_page
) {
112 const GURL
& url
= chrome::GetSettingsUrl(sub_page
);
113 ui_test_utils::NavigateToURLWithDisposition(browser(), url
, CURRENT_TAB
, 0);
115 content::WebContents
* web_contents
=
116 browser()->tab_strip_model()->GetActiveWebContents();
117 ASSERT_TRUE(web_contents
);
118 ASSERT_TRUE(web_contents
->GetWebUI());
119 UberUI
* uber_ui
= static_cast<UberUI
*>(
120 web_contents
->GetWebUI()->GetController());
121 OptionsUI
* options_ui
= static_cast<OptionsUI
*>(
122 uber_ui
->GetSubpage(chrome::kChromeUISettingsFrameURL
)->GetController());
124 // It is not possible to subscribe to the OnFinishedLoading event before the
125 // call to NavigateToURL(), because the WebUI does not yet exist at that time.
126 // However, it is safe to subscribe afterwards, because the event will always
127 // be posted asynchronously to the message loop.
128 scoped_refptr
<MessageLoopRunner
> message_loop_runner(new MessageLoopRunner
);
129 scoped_ptr
<OptionsUI::OnFinishedLoadingCallbackList::Subscription
>
130 subscription
= options_ui
->RegisterOnFinishedLoadingCallback(
131 message_loop_runner
->QuitClosure());
132 message_loop_runner
->Run();
135 void OptionsUIBrowserTest::NavigateToSettingsFrame() {
136 const GURL
& url
= GURL(chrome::kChromeUISettingsFrameURL
);
137 ui_test_utils::NavigateToURL(browser(), url
);
140 void OptionsUIBrowserTest::VerifyNavbar() {
141 bool navbar_exist
= false;
142 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
143 browser()->tab_strip_model()->GetActiveWebContents(),
144 "domAutomationController.send("
145 " !!document.getElementById('navigation'))",
147 EXPECT_EQ(true, navbar_exist
);
150 void OptionsUIBrowserTest::VerifyTitle() {
151 base::string16 title
=
152 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle();
153 base::string16 expected_title
= l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE
);
154 EXPECT_NE(title
.find(expected_title
), base::string16::npos
);
157 content::RenderFrameHost
* OptionsUIBrowserTest::GetSettingsFrame() {
158 // NB: The utility function content::FrameHasSourceUrl can't be used because
159 // the settings frame navigates itself to chrome://settings-frame/settings
160 // to indicate that it's showing the top-level settings. Therefore, just
162 return content::FrameMatchingPredicate(
163 browser()->tab_strip_model()->GetActiveWebContents(),
164 base::Bind(&FrameHasSettingsSourceHost
));
167 IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest
, LoadOptionsByURL
) {
168 NavigateToSettings();
173 // Flaky on win_rel when the profile is deleted crbug.com/103355
174 // Also related to crbug.com/104851
176 #define MAYBE_VerifyManagedSignout DISABLED_VerifyManagedSignout
178 #define MAYBE_VerifyManagedSignout VerifyManagedSignout
181 #if !defined(OS_CHROMEOS)
182 IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest
, MAYBE_VerifyManagedSignout
) {
183 SigninManager
* signin
=
184 SigninManagerFactory::GetForProfile(browser()->profile());
185 signin
->OnExternalSigninCompleted("test@example.com");
186 signin
->ProhibitSignout(true);
188 NavigateToSettingsFrame();
190 // This script simulates a click on the "Disconnect your Google Account"
191 // button and returns true if the hidden flag of the appropriate dialog gets
194 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
195 browser()->tab_strip_model()->GetActiveWebContents(),
196 "var dialog = $('manage-profile-overlay-disconnect-managed');"
197 "var original_status = dialog.hidden;"
198 "$('start-stop-sync').click();"
199 "domAutomationController.send(original_status && !dialog.hidden);",
204 base::FilePath profile_dir
= browser()->profile()->GetPath();
205 ProfileInfoCache
& profile_info_cache
=
206 g_browser_process
->profile_manager()->GetProfileInfoCache();
208 EXPECT_TRUE(DirectoryExists(profile_dir
));
209 EXPECT_TRUE(profile_info_cache
.GetIndexOfProfileWithPath(profile_dir
) !=
212 content::WindowedNotificationObserver
wait_for_profile_deletion(
213 chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED
,
214 content::NotificationService::AllSources());
216 // TODO(kaliamoorthi): Get the macos problem fixed and remove this code.
217 // Deleting the Profile also destroys all browser windows of that Profile.
218 // Wait for the current browser to close before resuming, otherwise
219 // the browser_tests shutdown code will be confused on the Mac.
220 content::WindowedNotificationObserver
wait_for_browser_closed(
221 chrome::NOTIFICATION_BROWSER_CLOSED
,
222 content::NotificationService::AllSources());
224 ASSERT_TRUE(content::ExecuteScript(
225 browser()->tab_strip_model()->GetActiveWebContents(),
226 "$('disconnect-managed-profile-ok').click();"));
228 wait_for_profile_deletion
.Wait();
230 EXPECT_TRUE(profile_info_cache
.GetIndexOfProfileWithPath(profile_dir
) ==
233 wait_for_browser_closed
.Wait();
236 IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest
, VerifyUnmanagedSignout
) {
237 SigninManager
* signin
=
238 SigninManagerFactory::GetForProfile(browser()->profile());
239 const std::string user
= "test@example.com";
240 signin
->OnExternalSigninCompleted(user
);
242 NavigateToSettingsFrame();
244 // This script simulates a click on the "Disconnect your Google Account"
245 // button and returns true if the hidden flag of the appropriate dialog gets
248 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
249 browser()->tab_strip_model()->GetActiveWebContents(),
250 "var dialog = $('sync-setup-stop-syncing');"
251 "var original_status = dialog.hidden;"
252 "$('start-stop-sync').click();"
253 "domAutomationController.send(original_status && !dialog.hidden);",
258 SignOutWaiter
sign_out_waiter(signin
);
260 ASSERT_TRUE(content::ExecuteScript(
261 browser()->tab_strip_model()->GetActiveWebContents(),
262 "$('stop-syncing-ok').click();"));
264 sign_out_waiter
.Wait();
266 EXPECT_TRUE(browser()->profile()->GetProfileName() != user
);
267 EXPECT_TRUE(signin
->GetAuthenticatedUsername().empty());
270 // Regression test for http://crbug.com/301436, excluded on Chrome OS because
271 // profile management in the settings UI exists on desktop platforms only.
272 IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest
, NavigateBackFromOverlayDialog
) {
273 NavigateToSettingsFrame();
275 // Click a button that opens an overlay dialog.
276 content::WebContents
* contents
=
277 browser()->tab_strip_model()->GetActiveWebContents();
278 ASSERT_TRUE(content::ExecuteScript(
279 contents
, "$('manage-default-search-engines').click();"));
281 // Go back to the settings page.
282 content::TestNavigationObserver
observer(contents
);
283 chrome::GoBack(browser(), CURRENT_TAB
);
286 // Verify that the settings page lists one profile.
287 const char javascript
[] =
288 "domAutomationController.send("
289 " document.querySelectorAll('list#profiles-list > div[role=listitem]')"
292 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
293 contents
, javascript
, &profiles
));
294 EXPECT_EQ(1, profiles
);
296 // Create a second profile.
297 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
298 const base::FilePath profile_path
=
299 profile_manager
->GenerateNextProfileDirectoryPath();
301 base::RunLoop run_loop
;
302 profile_manager
->CreateProfileAsync(
303 profile_manager
->GenerateNextProfileDirectoryPath(),
304 base::Bind(&RunClosureWhenProfileInitialized
,
305 run_loop
.QuitClosure()),
311 // Verify that the settings page has updated and lists two profiles.
312 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
313 contents
, javascript
, &profiles
));
314 EXPECT_EQ(2, profiles
);
318 } // namespace options