ui_test_utils.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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. 4 5#include "chrome/test/base/ui_test_utils.h" 6 7#if defined(OS_WIN) 8#include <windows.h> 9#endif 10 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/extensions/extension_action.h" 33#include "chrome/browser/history/history_service_factory.h" 34#include "chrome/browser/profiles/profile.h" 35#include "chrome/browser/search_engines/template_url_service.h" 36#include "chrome/browser/search_engines/template_url_service_test_util.h" 37#include "chrome/browser/thumbnails/render_widget_snapshot_taker.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/browser_thread.h" 57#include "content/public/browser/dom_operation_notification_details.h" 58#include "content/public/browser/download_item.h" 59#include "content/public/browser/download_manager.h" 60#include "content/public/browser/geolocation_provider.h" 61#include "content/public/browser/navigation_controller.h" 62#include "content/public/browser/navigation_entry.h" 63#include "content/public/browser/notification_service.h" 64#include "content/public/browser/render_process_host.h" 65#include "content/public/browser/render_view_host.h" 66#include "content/public/browser/web_contents.h" 67#include "content/public/browser/web_contents_observer.h" 68#include "content/public/browser/web_contents_view.h" 69#include "content/public/common/geoposition.h" 70#include "content/public/test/browser_test_utils.h" 71#include "content/public/test/download_test_observer.h" 72#include "content/public/test/test_navigation_observer.h" 73#include "content/public/test/test_utils.h" 74#include "net/base/net_util.h" 75#include "net/test/python_utils.h" 76#include "third_party/skia/include/core/SkBitmap.h" 77#include "third_party/skia/include/core/SkColor.h" 78#include "ui/gfx/size.h" 79#include "ui/snapshot/test/snapshot_desktop.h" 80 81#if defined(USE_AURA) 82#include "ash/shell.h" 83#include "ui/aura/root_window.h" 84#endif 85 86using content::BrowserThread; 87using content::DomOperationNotificationDetails; 88using content::NativeWebKeyboardEvent; 89using content::NavigationController; 90using content::NavigationEntry; 91using content::OpenURLParams; 92using content::RenderViewHost; 93using content::RenderWidgetHost; 94using content::Referrer; 95using content::WebContents; 96 97namespace ui_test_utils { 98 99namespace { 100 101#if defined(OS_WIN) 102const char kSnapshotBaseName[] = "ChromiumSnapshot"; 103const char kSnapshotExtension[] = ".png"; 104 105base::FilePath GetSnapshotFileName(const base::FilePath& snapshot_directory) { 106 base::Time::Exploded the_time; 107 108 base::Time::Now().LocalExplode(&the_time); 109 std::string filename(base::StringPrintf("%s%04d%02d%02d%02d%02d%02d%s", 110 kSnapshotBaseName, the_time.year, the_time.month, the_time.day_of_month, 111 the_time.hour, the_time.minute, the_time.second, kSnapshotExtension)); 112 113 base::FilePath snapshot_file = snapshot_directory.AppendASCII(filename); 114 if (base::PathExists(snapshot_file)) { 115 int index = 0; 116 std::string suffix; 117 base::FilePath trial_file; 118 do { 119 suffix = base::StringPrintf(" (%d)", ++index); 120 trial_file = snapshot_file.InsertBeforeExtensionASCII(suffix); 121 } while (base::PathExists(trial_file)); 122 snapshot_file = trial_file; 123 } 124 return snapshot_file; 125} 126#endif // defined(OS_WIN) 127 128Browser* WaitForBrowserNotInSet(std::set<Browser*> excluded_browsers) { 129 Browser* new_browser = GetBrowserNotInSet(excluded_browsers); 130 if (new_browser == NULL) { 131 BrowserAddedObserver observer; 132 new_browser = observer.WaitForSingleNewBrowser(); 133 // The new browser should never be in |excluded_browsers|. 134 DCHECK(!ContainsKey(excluded_browsers, new_browser)); 135 } 136 return new_browser; 137} 138 139} // namespace 140 141bool GetCurrentTabTitle(const Browser* browser, string16* title) { 142 WebContents* web_contents = 143 browser->tab_strip_model()->GetActiveWebContents(); 144 if (!web_contents) 145 return false; 146 NavigationEntry* last_entry = web_contents->GetController().GetActiveEntry(); 147 if (!last_entry) 148 return false; 149 title->assign(last_entry->GetTitleForDisplay(std::string())); 150 return true; 151} 152 153Browser* OpenURLOffTheRecord(Profile* profile, const GURL& url) { 154 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop(); 155 chrome::OpenURLOffTheRecord(profile, url, active_desktop); 156 Browser* browser = chrome::FindTabbedBrowser( 157 profile->GetOffTheRecordProfile(), false, active_desktop); 158 content::TestNavigationObserver observer( 159 browser->tab_strip_model()->GetActiveWebContents()); 160 observer.Wait(); 161 return browser; 162} 163 164void NavigateToURL(chrome::NavigateParams* params) { 165 chrome::Navigate(params); 166 content::WaitForLoadStop(params->target_contents); 167} 168 169 170void NavigateToURLWithPost(Browser* browser, const GURL& url) { 171 chrome::NavigateParams params(browser, url, 172 content::PAGE_TRANSITION_FORM_SUBMIT); 173 params.uses_post = true; 174 NavigateToURL(¶ms); 175} 176 177void NavigateToURL(Browser* browser, const GURL& url) { 178 NavigateToURLWithDisposition(browser, url, CURRENT_TAB, 179 BROWSER_TEST_WAIT_FOR_NAVIGATION); 180} 181 182// Navigates the specified tab (via |disposition|) of |browser| to |url|, 183// blocking until the |number_of_navigations| specified complete. 184// |disposition| indicates what tab the download occurs in, and 185// |browser_test_flags| controls what to wait for before continuing. 186static void NavigateToURLWithDispositionBlockUntilNavigationsComplete( 187 Browser* browser, 188 const GURL& url, 189 int number_of_navigations, 190 WindowOpenDisposition disposition, 191 int browser_test_flags) { 192 TabStripModel* tab_strip = browser->tab_strip_model(); 193 if (disposition == CURRENT_TAB && tab_strip->GetActiveWebContents()) 194 content::WaitForLoadStop(tab_strip->GetActiveWebContents()); 195 content::TestNavigationObserver same_tab_observer( 196 tab_strip->GetActiveWebContents(), 197 number_of_navigations); 198 199 std::set<Browser*> initial_browsers; 200 for (chrome::BrowserIterator it; !it.done(); it.Next()) 201 initial_browsers.insert(*it); 202 203 content::WindowedNotificationObserver tab_added_observer( 204 chrome::NOTIFICATION_TAB_ADDED, 205 content::NotificationService::AllSources()); 206 207 browser->OpenURL(OpenURLParams( 208 url, Referrer(), disposition, content::PAGE_TRANSITION_TYPED, false)); 209 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_BROWSER) 210 browser = WaitForBrowserNotInSet(initial_browsers); 211 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_TAB) 212 tab_added_observer.Wait(); 213 if (!(browser_test_flags & BROWSER_TEST_WAIT_FOR_NAVIGATION)) { 214 // Some other flag caused the wait prior to this. 215 return; 216 } 217 WebContents* web_contents = NULL; 218 if (disposition == NEW_BACKGROUND_TAB) { 219 // We've opened up a new tab, but not selected it. 220 TabStripModel* tab_strip = browser->tab_strip_model(); 221 web_contents = tab_strip->GetWebContentsAt(tab_strip->active_index() + 1); 222 EXPECT_TRUE(web_contents != NULL) 223 << " Unable to wait for navigation to \"" << url.spec() 224 << "\" because the new tab is not available yet"; 225 if (!web_contents) 226 return; 227 } else if ((disposition == CURRENT_TAB) || 228 (disposition == NEW_FOREGROUND_TAB) || 229 (disposition == SINGLETON_TAB)) { 230 // The currently selected tab is the right one. 231 web_contents = browser->tab_strip_model()->GetActiveWebContents(); 232 } 233 if (disposition == CURRENT_TAB) { 234 same_tab_observer.Wait(); 235 return; 236 } else if (web_contents) { 237 content::TestNavigationObserver observer(web_contents, 238 number_of_navigations); 239 observer.Wait(); 240 return; 241 } 242 EXPECT_TRUE(NULL != web_contents) << " Unable to wait for navigation to \"" 243 << url.spec() << "\"" 244 << " because we can't get the tab contents"; 245} 246 247void NavigateToURLWithDisposition(Browser* browser, 248 const GURL& url, 249 WindowOpenDisposition disposition, 250 int browser_test_flags) { 251 NavigateToURLWithDispositionBlockUntilNavigationsComplete( 252 browser, 253 url, 254 1, 255 disposition, 256 browser_test_flags); 257} 258 259void NavigateToURLBlockUntilNavigationsComplete(Browser* browser, 260 const GURL& url, 261 int number_of_navigations) { 262 NavigateToURLWithDispositionBlockUntilNavigationsComplete( 263 browser, 264 url, 265 number_of_navigations, 266 CURRENT_TAB, 267 BROWSER_TEST_WAIT_FOR_NAVIGATION); 268} 269 270base::FilePath GetTestFilePath(const base::FilePath& dir, 271 const base::FilePath& file) { 272 base::FilePath path; 273 PathService::Get(chrome::DIR_TEST_DATA, &path); 274 return path.Append(dir).Append(file); 275} 276 277GURL GetTestUrl(const base::FilePath& dir, const base::FilePath& file) { 278 return net::FilePathToFileURL(GetTestFilePath(dir, file)); 279} 280 281bool GetRelativeBuildDirectory(base::FilePath* build_dir) { 282 // This function is used to find the build directory so TestServer can serve 283 // built files (nexes, etc). TestServer expects a path relative to the source 284 // root. 285 base::FilePath exe_dir = 286 CommandLine::ForCurrentProcess()->GetProgram().DirName(); 287 base::FilePath src_dir; 288 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) 289 return false; 290 291 // We must first generate absolute paths to SRC and EXE and from there 292 // generate a relative path. 293 if (!exe_dir.IsAbsolute()) 294 exe_dir = base::MakeAbsoluteFilePath(exe_dir); 295 if (!src_dir.IsAbsolute()) 296 src_dir = base::MakeAbsoluteFilePath(src_dir); 297 if (!exe_dir.IsAbsolute()) 298 return false; 299 if (!src_dir.IsAbsolute()) 300 return false; 301 302 size_t match, exe_size, src_size; 303 std::vector<base::FilePath::StringType> src_parts, exe_parts; 304 305 // Determine point at which src and exe diverge. 306 exe_dir.GetComponents(&exe_parts); 307 src_dir.GetComponents(&src_parts); 308 exe_size = exe_parts.size(); 309 src_size = src_parts.size(); 310 for (match = 0; match < exe_size && match < src_size; ++match) { 311 if (exe_parts[match] != src_parts[match]) 312 break; 313 } 314 315 // Create a relative path. 316 *build_dir = base::FilePath(); 317 for (size_t tmp_itr = match; tmp_itr < src_size; ++tmp_itr) 318 *build_dir = build_dir->Append(FILE_PATH_LITERAL("..")); 319 for (; match < exe_size; ++match) 320 *build_dir = build_dir->Append(exe_parts[match]); 321 return true; 322} 323 324AppModalDialog* WaitForAppModalDialog() { 325 AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance(); 326 if (dialog_queue->HasActiveDialog()) 327 return dialog_queue->active_dialog(); 328 329 content::WindowedNotificationObserver observer( 330 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 331 content::NotificationService::AllSources()); 332 observer.Wait(); 333 return content::Source<AppModalDialog>(observer.source()).ptr(); 334} 335 336int FindInPage(WebContents* tab, const string16& search_string, 337 bool forward, bool match_case, int* ordinal, 338 gfx::Rect* selection_rect) { 339 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(tab); 340 find_tab_helper->StartFinding(search_string, forward, match_case); 341 FindInPageNotificationObserver observer(tab); 342 observer.Wait(); 343 if (ordinal) 344 *ordinal = observer.active_match_ordinal(); 345 if (selection_rect) 346 *selection_rect = observer.selection_rect(); 347 return observer.number_of_matches(); 348} 349 350void WaitForTemplateURLServiceToLoad(TemplateURLService* service) { 351 if (service->loaded()) 352 return; 353 scoped_refptr<content::MessageLoopRunner> message_loop_runner = 354 new content::MessageLoopRunner; 355 scoped_ptr<TemplateURLService::Subscription> subscription = 356 service->RegisterOnLoadedCallback( 357 message_loop_runner->QuitClosure()); 358 service->Load(); 359 message_loop_runner->Run(); 360 361 ASSERT_TRUE(service->loaded()); 362} 363 364void WaitForHistoryToLoad(HistoryService* history_service) { 365 content::WindowedNotificationObserver history_loaded_observer( 366 chrome::NOTIFICATION_HISTORY_LOADED, 367 content::NotificationService::AllSources()); 368 if (!history_service->BackendLoaded()) 369 history_loaded_observer.Wait(); 370} 371 372void DownloadURL(Browser* browser, const GURL& download_url) { 373 base::ScopedTempDir downloads_directory; 374 ASSERT_TRUE(downloads_directory.CreateUniqueTempDir()); 375 browser->profile()->GetPrefs()->SetFilePath( 376 prefs::kDownloadDefaultDirectory, downloads_directory.path()); 377 378 content::DownloadManager* download_manager = 379 content::BrowserContext::GetDownloadManager(browser->profile()); 380 scoped_ptr<content::DownloadTestObserver> observer( 381 new content::DownloadTestObserverTerminal( 382 download_manager, 1, 383 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT)); 384 385 ui_test_utils::NavigateToURL(browser, download_url); 386 observer->WaitForFinished(); 387} 388 389void SendToOmniboxAndSubmit(LocationBar* location_bar, 390 const std::string& input) { 391 OmniboxView* omnibox = location_bar->GetOmniboxView(); 392 omnibox->model()->OnSetFocus(false); 393 omnibox->SetUserText(ASCIIToUTF16(input)); 394 location_bar->AcceptInput(); 395 while (!omnibox->model()->autocomplete_controller()->done()) { 396 content::WindowedNotificationObserver observer( 397 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, 398 content::NotificationService::AllSources()); 399 observer.Wait(); 400 } 401} 402 403Browser* GetBrowserNotInSet(std::set<Browser*> excluded_browsers) { 404 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 405 if (excluded_browsers.find(*it) == excluded_browsers.end()) 406 return *it; 407 } 408 return NULL; 409} 410 411WindowedTabAddedNotificationObserver::WindowedTabAddedNotificationObserver( 412 const content::NotificationSource& source) 413 : WindowedNotificationObserver(chrome::NOTIFICATION_TAB_ADDED, source), 414 added_tab_(NULL) { 415} 416 417void WindowedTabAddedNotificationObserver::Observe( 418 int type, 419 const content::NotificationSource& source, 420 const content::NotificationDetails& details) { 421 added_tab_ = content::Details<WebContents>(details).ptr(); 422 content::WindowedNotificationObserver::Observe(type, source, details); 423} 424 425UrlLoadObserver::UrlLoadObserver(const GURL& url, 426 const content::NotificationSource& source) 427 : WindowedNotificationObserver(content::NOTIFICATION_LOAD_STOP, source), 428 url_(url) { 429} 430 431UrlLoadObserver::~UrlLoadObserver() {} 432 433void UrlLoadObserver::Observe( 434 int type, 435 const content::NotificationSource& source, 436 const content::NotificationDetails& details) { 437 NavigationController* controller = 438 content::Source<NavigationController>(source).ptr(); 439 if (controller->GetWebContents()->GetURL() != url_) 440 return; 441 442 WindowedNotificationObserver::Observe(type, source, details); 443} 444 445BrowserAddedObserver::BrowserAddedObserver() 446 : notification_observer_( 447 chrome::NOTIFICATION_BROWSER_OPENED, 448 content::NotificationService::AllSources()) { 449 for (chrome::BrowserIterator it; !it.done(); it.Next()) 450 original_browsers_.insert(*it); 451} 452 453BrowserAddedObserver::~BrowserAddedObserver() { 454} 455 456Browser* BrowserAddedObserver::WaitForSingleNewBrowser() { 457 notification_observer_.Wait(); 458 // Ensure that only a single new browser has appeared. 459 EXPECT_EQ(original_browsers_.size() + 1, chrome::GetTotalBrowserCount()); 460 return GetBrowserNotInSet(original_browsers_); 461} 462 463#if defined(OS_WIN) 464 465bool SaveScreenSnapshotToDirectory(const base::FilePath& directory, 466 base::FilePath* screenshot_path) { 467 bool succeeded = false; 468 base::FilePath out_path(GetSnapshotFileName(directory)); 469 470 MONITORINFO monitor_info = {}; 471 monitor_info.cbSize = sizeof(monitor_info); 472 HMONITOR main_monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY); 473 if (GetMonitorInfo(main_monitor, &monitor_info)) { 474 RECT& rect = monitor_info.rcMonitor; 475 476 std::vector<unsigned char> png_data; 477 gfx::Rect bounds( 478 gfx::Size(rect.right - rect.left, rect.bottom - rect.top)); 479 if (ui::GrabDesktopSnapshot(bounds, &png_data) && 480 png_data.size() <= INT_MAX) { 481 int bytes = static_cast<int>(png_data.size()); 482 int written = file_util::WriteFile( 483 out_path, reinterpret_cast<char*>(&png_data[0]), bytes); 484 succeeded = (written == bytes); 485 } 486 } 487 488 if (succeeded && screenshot_path != NULL) 489 *screenshot_path = out_path; 490 491 return succeeded; 492} 493 494bool SaveScreenSnapshotToDesktop(base::FilePath* screenshot_path) { 495 base::FilePath desktop; 496 497 return PathService::Get(base::DIR_USER_DESKTOP, &desktop) && 498 SaveScreenSnapshotToDirectory(desktop, screenshot_path); 499} 500 501#endif // defined(OS_WIN) 502 503void OverrideGeolocation(double latitude, double longitude) { 504 content::Geoposition position; 505 position.latitude = latitude; 506 position.longitude = longitude; 507 position.altitude = 0.; 508 position.accuracy = 0.; 509 position.timestamp = base::Time::Now(); 510 scoped_refptr<content::MessageLoopRunner> runner = 511 new content::MessageLoopRunner; 512 513 content::GeolocationProvider::OverrideLocationForTesting( 514 position, runner->QuitClosure()); 515 516 runner->Run(); 517} 518 519HistoryEnumerator::HistoryEnumerator(Profile* profile) { 520 scoped_refptr<content::MessageLoopRunner> message_loop_runner = 521 new content::MessageLoopRunner; 522 523 HistoryService* hs = HistoryServiceFactory::GetForProfile( 524 profile, Profile::EXPLICIT_ACCESS); 525 hs->QueryHistory( 526 string16(), 527 history::QueryOptions(), 528 &consumer_, 529 base::Bind(&HistoryEnumerator::HistoryQueryComplete, 530 base::Unretained(this), message_loop_runner->QuitClosure())); 531 message_loop_runner->Run(); 532} 533 534HistoryEnumerator::~HistoryEnumerator() {} 535 536void HistoryEnumerator::HistoryQueryComplete( 537 const base::Closure& quit_task, 538 HistoryService::Handle request_handle, 539 history::QueryResults* results) { 540 for (size_t i = 0; i < results->size(); ++i) 541 urls_.push_back((*results)[i].url()); 542 quit_task.Run(); 543} 544 545} // namespace ui_test_utils 546