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