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/test/base/ui_test_utils.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/files/file_path.h"
17 #include "base/json/json_reader.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/path_service.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/test/test_timeouts.h"
25 #include "base/time/time.h"
26 #include "base/values.h"
27 #include "chrome/browser/autocomplete/autocomplete_controller.h"
28 #include "chrome/browser/bookmarks/bookmark_model.h"
29 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/chrome_notification_types.h"
32 #include "chrome/browser/devtools/devtools_window.h"
33 #include "chrome/browser/extensions/extension_action.h"
34 #include "chrome/browser/history/history_service_factory.h"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/browser/search_engines/template_url_service.h"
37 #include "chrome/browser/search_engines/template_url_service_test_util.h"
38 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
39 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
40 #include "chrome/browser/ui/browser.h"
41 #include "chrome/browser/ui/browser_commands.h"
42 #include "chrome/browser/ui/browser_finder.h"
43 #include "chrome/browser/ui/browser_iterator.h"
44 #include "chrome/browser/ui/browser_list.h"
45 #include "chrome/browser/ui/browser_navigator.h"
46 #include "chrome/browser/ui/browser_window.h"
47 #include "chrome/browser/ui/find_bar/find_notification_details.h"
48 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
49 #include "chrome/browser/ui/host_desktop.h"
50 #include "chrome/browser/ui/omnibox/location_bar.h"
51 #include "chrome/browser/ui/omnibox/omnibox_view.h"
52 #include "chrome/browser/ui/tabs/tab_strip_model.h"
53 #include "chrome/common/chrome_paths.h"
54 #include "chrome/common/pref_names.h"
55 #include "chrome/test/base/find_in_page_observer.h"
56 #include "content/public/browser/dom_operation_notification_details.h"
57 #include "content/public/browser/download_item.h"
58 #include "content/public/browser/download_manager.h"
59 #include "content/public/browser/geolocation_provider.h"
60 #include "content/public/browser/navigation_controller.h"
61 #include "content/public/browser/navigation_entry.h"
62 #include "content/public/browser/notification_service.h"
63 #include "content/public/browser/render_process_host.h"
64 #include "content/public/browser/render_view_host.h"
65 #include "content/public/browser/web_contents.h"
66 #include "content/public/browser/web_contents_observer.h"
67 #include "content/public/browser/web_contents_view.h"
68 #include "content/public/common/geoposition.h"
69 #include "content/public/test/browser_test_utils.h"
70 #include "content/public/test/download_test_observer.h"
71 #include "content/public/test/test_navigation_observer.h"
72 #include "content/public/test/test_utils.h"
73 #include "net/base/net_util.h"
74 #include "net/test/python_utils.h"
75 #include "third_party/skia/include/core/SkBitmap.h"
76 #include "third_party/skia/include/core/SkColor.h"
77 #include "ui/gfx/size.h"
78 #include "ui/snapshot/test/snapshot_desktop.h"
81 #include "ash/shell.h"
82 #include "ui/aura/window_event_dispatcher.h"
85 using content::DomOperationNotificationDetails
;
86 using content::NativeWebKeyboardEvent
;
87 using content::NavigationController
;
88 using content::NavigationEntry
;
89 using content::OpenURLParams
;
90 using content::RenderViewHost
;
91 using content::RenderWidgetHost
;
92 using content::Referrer
;
93 using content::WebContents
;
95 namespace ui_test_utils
{
100 const char kSnapshotBaseName
[] = "ChromiumSnapshot";
101 const char kSnapshotExtension
[] = ".png";
103 base::FilePath
GetSnapshotFileName(const base::FilePath
& snapshot_directory
) {
104 base::Time::Exploded the_time
;
106 base::Time::Now().LocalExplode(&the_time
);
107 std::string
filename(base::StringPrintf("%s%04d%02d%02d%02d%02d%02d%s",
108 kSnapshotBaseName
, the_time
.year
, the_time
.month
, the_time
.day_of_month
,
109 the_time
.hour
, the_time
.minute
, the_time
.second
, kSnapshotExtension
));
111 base::FilePath snapshot_file
= snapshot_directory
.AppendASCII(filename
);
112 if (base::PathExists(snapshot_file
)) {
115 base::FilePath trial_file
;
117 suffix
= base::StringPrintf(" (%d)", ++index
);
118 trial_file
= snapshot_file
.InsertBeforeExtensionASCII(suffix
);
119 } while (base::PathExists(trial_file
));
120 snapshot_file
= trial_file
;
122 return snapshot_file
;
124 #endif // defined(OS_WIN)
126 Browser
* WaitForBrowserNotInSet(std::set
<Browser
*> excluded_browsers
) {
127 Browser
* new_browser
= GetBrowserNotInSet(excluded_browsers
);
128 if (new_browser
== NULL
) {
129 BrowserAddedObserver observer
;
130 new_browser
= observer
.WaitForSingleNewBrowser();
131 // The new browser should never be in |excluded_browsers|.
132 DCHECK(!ContainsKey(excluded_browsers
, new_browser
));
139 bool GetCurrentTabTitle(const Browser
* browser
, base::string16
* title
) {
140 WebContents
* web_contents
=
141 browser
->tab_strip_model()->GetActiveWebContents();
144 NavigationEntry
* last_entry
= web_contents
->GetController().GetActiveEntry();
147 title
->assign(last_entry
->GetTitleForDisplay(std::string()));
151 Browser
* OpenURLOffTheRecord(Profile
* profile
, const GURL
& url
) {
152 chrome::HostDesktopType active_desktop
= chrome::GetActiveDesktop();
153 chrome::OpenURLOffTheRecord(profile
, url
, active_desktop
);
154 Browser
* browser
= chrome::FindTabbedBrowser(
155 profile
->GetOffTheRecordProfile(), false, active_desktop
);
156 content::TestNavigationObserver
observer(
157 browser
->tab_strip_model()->GetActiveWebContents());
162 void NavigateToURL(chrome::NavigateParams
* params
) {
163 chrome::Navigate(params
);
164 content::WaitForLoadStop(params
->target_contents
);
168 void NavigateToURLWithPost(Browser
* browser
, const GURL
& url
) {
169 chrome::NavigateParams
params(browser
, url
,
170 content::PAGE_TRANSITION_FORM_SUBMIT
);
171 params
.uses_post
= true;
172 NavigateToURL(¶ms
);
175 void NavigateToURL(Browser
* browser
, const GURL
& url
) {
176 NavigateToURLWithDisposition(browser
, url
, CURRENT_TAB
,
177 BROWSER_TEST_WAIT_FOR_NAVIGATION
);
180 // Navigates the specified tab (via |disposition|) of |browser| to |url|,
181 // blocking until the |number_of_navigations| specified complete.
182 // |disposition| indicates what tab the download occurs in, and
183 // |browser_test_flags| controls what to wait for before continuing.
184 static void NavigateToURLWithDispositionBlockUntilNavigationsComplete(
187 int number_of_navigations
,
188 WindowOpenDisposition disposition
,
189 int browser_test_flags
) {
190 TabStripModel
* tab_strip
= browser
->tab_strip_model();
191 if (disposition
== CURRENT_TAB
&& tab_strip
->GetActiveWebContents())
192 content::WaitForLoadStop(tab_strip
->GetActiveWebContents());
193 content::TestNavigationObserver
same_tab_observer(
194 tab_strip
->GetActiveWebContents(),
195 number_of_navigations
);
197 std::set
<Browser
*> initial_browsers
;
198 for (chrome::BrowserIterator it
; !it
.done(); it
.Next())
199 initial_browsers
.insert(*it
);
201 content::WindowedNotificationObserver
tab_added_observer(
202 chrome::NOTIFICATION_TAB_ADDED
,
203 content::NotificationService::AllSources());
205 browser
->OpenURL(OpenURLParams(
206 url
, Referrer(), disposition
, content::PAGE_TRANSITION_TYPED
, false));
207 if (browser_test_flags
& BROWSER_TEST_WAIT_FOR_BROWSER
)
208 browser
= WaitForBrowserNotInSet(initial_browsers
);
209 if (browser_test_flags
& BROWSER_TEST_WAIT_FOR_TAB
)
210 tab_added_observer
.Wait();
211 if (!(browser_test_flags
& BROWSER_TEST_WAIT_FOR_NAVIGATION
)) {
212 // Some other flag caused the wait prior to this.
215 WebContents
* web_contents
= NULL
;
216 if (disposition
== NEW_BACKGROUND_TAB
) {
217 // We've opened up a new tab, but not selected it.
218 TabStripModel
* tab_strip
= browser
->tab_strip_model();
219 web_contents
= tab_strip
->GetWebContentsAt(tab_strip
->active_index() + 1);
220 EXPECT_TRUE(web_contents
!= NULL
)
221 << " Unable to wait for navigation to \"" << url
.spec()
222 << "\" because the new tab is not available yet";
225 } else if ((disposition
== CURRENT_TAB
) ||
226 (disposition
== NEW_FOREGROUND_TAB
) ||
227 (disposition
== SINGLETON_TAB
)) {
228 // The currently selected tab is the right one.
229 web_contents
= browser
->tab_strip_model()->GetActiveWebContents();
231 if (disposition
== CURRENT_TAB
) {
232 same_tab_observer
.Wait();
234 } else if (web_contents
) {
235 content::TestNavigationObserver
observer(web_contents
,
236 number_of_navigations
);
240 EXPECT_TRUE(NULL
!= web_contents
) << " Unable to wait for navigation to \""
241 << url
.spec() << "\""
242 << " because we can't get the tab contents";
245 void NavigateToURLWithDisposition(Browser
* browser
,
247 WindowOpenDisposition disposition
,
248 int browser_test_flags
) {
249 NavigateToURLWithDispositionBlockUntilNavigationsComplete(
257 void NavigateToURLBlockUntilNavigationsComplete(Browser
* browser
,
259 int number_of_navigations
) {
260 NavigateToURLWithDispositionBlockUntilNavigationsComplete(
263 number_of_navigations
,
265 BROWSER_TEST_WAIT_FOR_NAVIGATION
);
268 void WaitUntilDevToolsWindowLoaded(DevToolsWindow
* window
) {
269 scoped_refptr
<content::MessageLoopRunner
> runner
=
270 new content::MessageLoopRunner
;
271 window
->SetLoadCompletedCallback(runner
->QuitClosure());
275 base::FilePath
GetTestFilePath(const base::FilePath
& dir
,
276 const base::FilePath
& file
) {
278 PathService::Get(chrome::DIR_TEST_DATA
, &path
);
279 return path
.Append(dir
).Append(file
);
282 GURL
GetTestUrl(const base::FilePath
& dir
, const base::FilePath
& file
) {
283 return net::FilePathToFileURL(GetTestFilePath(dir
, file
));
286 bool GetRelativeBuildDirectory(base::FilePath
* build_dir
) {
287 // This function is used to find the build directory so TestServer can serve
288 // built files (nexes, etc). TestServer expects a path relative to the source
290 base::FilePath exe_dir
=
291 CommandLine::ForCurrentProcess()->GetProgram().DirName();
292 base::FilePath src_dir
;
293 if (!PathService::Get(base::DIR_SOURCE_ROOT
, &src_dir
))
296 // We must first generate absolute paths to SRC and EXE and from there
297 // generate a relative path.
298 if (!exe_dir
.IsAbsolute())
299 exe_dir
= base::MakeAbsoluteFilePath(exe_dir
);
300 if (!src_dir
.IsAbsolute())
301 src_dir
= base::MakeAbsoluteFilePath(src_dir
);
302 if (!exe_dir
.IsAbsolute())
304 if (!src_dir
.IsAbsolute())
307 size_t match
, exe_size
, src_size
;
308 std::vector
<base::FilePath::StringType
> src_parts
, exe_parts
;
310 // Determine point at which src and exe diverge.
311 exe_dir
.GetComponents(&exe_parts
);
312 src_dir
.GetComponents(&src_parts
);
313 exe_size
= exe_parts
.size();
314 src_size
= src_parts
.size();
315 for (match
= 0; match
< exe_size
&& match
< src_size
; ++match
) {
316 if (exe_parts
[match
] != src_parts
[match
])
320 // Create a relative path.
321 *build_dir
= base::FilePath();
322 for (size_t tmp_itr
= match
; tmp_itr
< src_size
; ++tmp_itr
)
323 *build_dir
= build_dir
->Append(FILE_PATH_LITERAL(".."));
324 for (; match
< exe_size
; ++match
)
325 *build_dir
= build_dir
->Append(exe_parts
[match
]);
329 AppModalDialog
* WaitForAppModalDialog() {
330 AppModalDialogQueue
* dialog_queue
= AppModalDialogQueue::GetInstance();
331 if (dialog_queue
->HasActiveDialog())
332 return dialog_queue
->active_dialog();
334 content::WindowedNotificationObserver
observer(
335 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN
,
336 content::NotificationService::AllSources());
338 return content::Source
<AppModalDialog
>(observer
.source()).ptr();
341 int FindInPage(WebContents
* tab
,
342 const base::string16
& search_string
,
346 gfx::Rect
* selection_rect
) {
347 FindTabHelper
* find_tab_helper
= FindTabHelper::FromWebContents(tab
);
348 find_tab_helper
->StartFinding(search_string
, forward
, match_case
);
349 FindInPageNotificationObserver
observer(tab
);
352 *ordinal
= observer
.active_match_ordinal();
354 *selection_rect
= observer
.selection_rect();
355 return observer
.number_of_matches();
358 void WaitForTemplateURLServiceToLoad(TemplateURLService
* service
) {
359 if (service
->loaded())
361 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner
=
362 new content::MessageLoopRunner
;
363 scoped_ptr
<TemplateURLService::Subscription
> subscription
=
364 service
->RegisterOnLoadedCallback(
365 message_loop_runner
->QuitClosure());
367 message_loop_runner
->Run();
369 ASSERT_TRUE(service
->loaded());
372 void WaitForHistoryToLoad(HistoryService
* history_service
) {
373 content::WindowedNotificationObserver
history_loaded_observer(
374 chrome::NOTIFICATION_HISTORY_LOADED
,
375 content::NotificationService::AllSources());
376 if (!history_service
->BackendLoaded())
377 history_loaded_observer
.Wait();
380 void DownloadURL(Browser
* browser
, const GURL
& download_url
) {
381 base::ScopedTempDir downloads_directory
;
382 ASSERT_TRUE(downloads_directory
.CreateUniqueTempDir());
383 browser
->profile()->GetPrefs()->SetFilePath(
384 prefs::kDownloadDefaultDirectory
, downloads_directory
.path());
386 content::DownloadManager
* download_manager
=
387 content::BrowserContext::GetDownloadManager(browser
->profile());
388 scoped_ptr
<content::DownloadTestObserver
> observer(
389 new content::DownloadTestObserverTerminal(
391 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT
));
393 ui_test_utils::NavigateToURL(browser
, download_url
);
394 observer
->WaitForFinished();
397 void SendToOmniboxAndSubmit(LocationBar
* location_bar
,
398 const std::string
& input
) {
399 OmniboxView
* omnibox
= location_bar
->GetOmniboxView();
400 omnibox
->model()->OnSetFocus(false);
401 omnibox
->SetUserText(base::ASCIIToUTF16(input
));
402 location_bar
->AcceptInput();
403 while (!omnibox
->model()->autocomplete_controller()->done()) {
404 content::WindowedNotificationObserver
observer(
405 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY
,
406 content::NotificationService::AllSources());
411 Browser
* GetBrowserNotInSet(std::set
<Browser
*> excluded_browsers
) {
412 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
413 if (excluded_browsers
.find(*it
) == excluded_browsers
.end())
419 WindowedTabAddedNotificationObserver::WindowedTabAddedNotificationObserver(
420 const content::NotificationSource
& source
)
421 : WindowedNotificationObserver(chrome::NOTIFICATION_TAB_ADDED
, source
),
425 void WindowedTabAddedNotificationObserver::Observe(
427 const content::NotificationSource
& source
,
428 const content::NotificationDetails
& details
) {
429 added_tab_
= content::Details
<WebContents
>(details
).ptr();
430 content::WindowedNotificationObserver::Observe(type
, source
, details
);
433 UrlLoadObserver::UrlLoadObserver(const GURL
& url
,
434 const content::NotificationSource
& source
)
435 : WindowedNotificationObserver(content::NOTIFICATION_LOAD_STOP
, source
),
439 UrlLoadObserver::~UrlLoadObserver() {}
441 void UrlLoadObserver::Observe(
443 const content::NotificationSource
& source
,
444 const content::NotificationDetails
& details
) {
445 NavigationController
* controller
=
446 content::Source
<NavigationController
>(source
).ptr();
447 if (controller
->GetWebContents()->GetURL() != url_
)
450 WindowedNotificationObserver::Observe(type
, source
, details
);
453 BrowserAddedObserver::BrowserAddedObserver()
454 : notification_observer_(
455 chrome::NOTIFICATION_BROWSER_OPENED
,
456 content::NotificationService::AllSources()) {
457 for (chrome::BrowserIterator it
; !it
.done(); it
.Next())
458 original_browsers_
.insert(*it
);
461 BrowserAddedObserver::~BrowserAddedObserver() {
464 Browser
* BrowserAddedObserver::WaitForSingleNewBrowser() {
465 notification_observer_
.Wait();
466 // Ensure that only a single new browser has appeared.
467 EXPECT_EQ(original_browsers_
.size() + 1, chrome::GetTotalBrowserCount());
468 return GetBrowserNotInSet(original_browsers_
);
473 bool SaveScreenSnapshotToDirectory(const base::FilePath
& directory
,
474 base::FilePath
* screenshot_path
) {
475 bool succeeded
= false;
476 base::FilePath
out_path(GetSnapshotFileName(directory
));
478 MONITORINFO monitor_info
= {};
479 monitor_info
.cbSize
= sizeof(monitor_info
);
480 HMONITOR main_monitor
= MonitorFromWindow(NULL
, MONITOR_DEFAULTTOPRIMARY
);
481 if (GetMonitorInfo(main_monitor
, &monitor_info
)) {
482 RECT
& rect
= monitor_info
.rcMonitor
;
484 std::vector
<unsigned char> png_data
;
486 gfx::Size(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
));
487 if (ui::GrabDesktopSnapshot(bounds
, &png_data
) &&
488 png_data
.size() <= INT_MAX
) {
489 int bytes
= static_cast<int>(png_data
.size());
490 int written
= file_util::WriteFile(
491 out_path
, reinterpret_cast<char*>(&png_data
[0]), bytes
);
492 succeeded
= (written
== bytes
);
496 if (succeeded
&& screenshot_path
!= NULL
)
497 *screenshot_path
= out_path
;
502 bool SaveScreenSnapshotToDesktop(base::FilePath
* screenshot_path
) {
503 base::FilePath desktop
;
505 return PathService::Get(base::DIR_USER_DESKTOP
, &desktop
) &&
506 SaveScreenSnapshotToDirectory(desktop
, screenshot_path
);
509 #endif // defined(OS_WIN)
511 void OverrideGeolocation(double latitude
, double longitude
) {
512 content::Geoposition position
;
513 position
.latitude
= latitude
;
514 position
.longitude
= longitude
;
515 position
.altitude
= 0.;
516 position
.accuracy
= 0.;
517 position
.timestamp
= base::Time::Now();
518 scoped_refptr
<content::MessageLoopRunner
> runner
=
519 new content::MessageLoopRunner
;
521 content::GeolocationProvider::OverrideLocationForTesting(
522 position
, runner
->QuitClosure());
527 HistoryEnumerator::HistoryEnumerator(Profile
* profile
) {
528 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner
=
529 new content::MessageLoopRunner
;
531 HistoryService
* hs
= HistoryServiceFactory::GetForProfile(
532 profile
, Profile::EXPLICIT_ACCESS
);
535 history::QueryOptions(),
537 base::Bind(&HistoryEnumerator::HistoryQueryComplete
,
538 base::Unretained(this), message_loop_runner
->QuitClosure()));
539 message_loop_runner
->Run();
542 HistoryEnumerator::~HistoryEnumerator() {}
544 void HistoryEnumerator::HistoryQueryComplete(
545 const base::Closure
& quit_task
,
546 HistoryService::Handle request_handle
,
547 history::QueryResults
* results
) {
548 for (size_t i
= 0; i
< results
->size(); ++i
)
549 urls_
.push_back((*results
)[i
].url());
553 } // namespace ui_test_utils