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 #ifndef CHROME_TEST_BASE_UI_TEST_UTILS_H_ 6 #define CHROME_TEST_BASE_UI_TEST_UTILS_H_ 7 8 #include <map> 9 #include <queue> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "base/scoped_observer.h" 15 #include "base/strings/string16.h" 16 #include "chrome/browser/ui/browser_list_observer.h" 17 #include "chrome/browser/ui/tabs/tab_strip_model.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 19 #include "chrome/browser/ui/view_ids.h" 20 #include "components/history/core/browser/history_service.h" 21 #include "content/public/browser/notification_details.h" 22 #include "content/public/browser/notification_observer.h" 23 #include "content/public/browser/notification_registrar.h" 24 #include "content/public/browser/notification_source.h" 25 #include "content/public/test/test_utils.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 #include "ui/base/window_open_disposition.h" 28 #include "ui/events/keycodes/keyboard_codes.h" 29 #include "ui/gfx/native_widget_types.h" 30 #include "url/gurl.h" 31 32 class Browser; 33 class Profile; 34 35 namespace javascript_dialogs { 36 class AppModalDialogController; 37 } 38 39 namespace base { 40 class FilePath; 41 } 42 43 struct NavigateParams; 44 45 namespace content { 46 class RenderProcessHost; 47 class WebContents; 48 } 49 50 namespace gfx { 51 class Rect; 52 } 53 54 // A collections of functions designed for use with InProcessBrowserTest. 55 namespace ui_test_utils { 56 57 // Flags to indicate what to wait for in a navigation test. 58 // They can be ORed together. 59 // The order in which the waits happen when more than one is selected, is: 60 // Browser 61 // Tab 62 // Navigation 63 enum BrowserTestWaitFlags { 64 // Don't wait for anything. 65 BROWSER_TEST_NONE = 0, 66 // Wait for a new browser. 67 BROWSER_TEST_WAIT_FOR_BROWSER = 1 << 0, 68 // Wait for a new tab. 69 BROWSER_TEST_WAIT_FOR_TAB = 1 << 1, 70 // Wait for loading to stop. Loading stops when either 71 // a document and its subresources are completely loaded 72 // (i.e. the spinner has stopped) or no document can be 73 // loaded due to an e.g. an error or crash. 74 BROWSER_TEST_WAIT_FOR_LOAD_STOP = 1 << 2, 75 76 BROWSER_TEST_MASK = BROWSER_TEST_WAIT_FOR_BROWSER | 77 BROWSER_TEST_WAIT_FOR_TAB | 78 BROWSER_TEST_WAIT_FOR_LOAD_STOP 79 }; 80 81 // Puts the current tab title in |title|. Returns true on success. 82 bool GetCurrentTabTitle(const Browser* browser, base::string16* title); 83 84 // Performs the provided navigation process, blocking until loading stops. 85 // See BROWSER_TEST_WAIT_FOR_LOAD_STOP. 86 // May change the params in some cases (i.e. if the navigation 87 // opens a new browser window). Uses chrome::Navigate. 88 // 89 // Note this does not return a RenderProcessHost for where the navigation 90 // occurs, so tests using this will be unable to verify the destruction of 91 // the RenderProcessHost when navigating again. 92 void NavigateToURL(NavigateParams* params); 93 94 // Navigates the selected tab of |browser| to |url|, blocking until 95 // loading stops. See BROWSER_TEST_WAIT_FOR_LOAD_STOP. Simulates a 96 // POST and uses chrome::Navigate. 97 // 98 // Note this does not return a RenderProcessHost for where the navigation 99 // occurs, so tests using this will be unable to verify the destruction of 100 // the RenderProcessHost when navigating again. 101 void NavigateToURLWithPost(Browser* browser, const GURL& url); 102 103 // Navigates the selected tab of |browser| to |url|, blocking until the 104 // loading stops. See BROWSER_TEST_WAIT_FOR_LOAD_STOP. Uses 105 // Browser::OpenURL --> chrome::Navigate. 106 // 107 // Returns a RenderProcessHost* for the renderer where the navigation 108 // occured. Use this when navigating again, when the test wants to wait not 109 // just for the navigation to complete but also for the previous 110 // RenderProcessHost to be torn down. Navigation does NOT imply the old 111 // RenderProcessHost is gone, and assuming so creates a race condition that 112 // can be exagerated by artifically slowing the FrameHostMsg_SwapOut_ACK reply 113 // from the renderer being navigated from. 114 content::RenderProcessHost* NavigateToURL(Browser* browser, const GURL& url); 115 116 // Navigates the specified tab of |browser| to |url|, blocking until the 117 // loading stops. 118 // |disposition| indicates what tab the navigation occurs in, and 119 // |browser_test_flags| controls what to wait for before continuing. 120 // 121 // If the |browser_test_flags| includes a request to wait for navigation, this 122 // returns a RenderProcessHost* for the renderer where the navigation 123 // occured. Use this when navigating again, when the test wants to wait not 124 // just for the navigation to complete but also for the previous 125 // RenderProcessHost to be torn down. Navigation does NOT imply the old 126 // RenderProcessHost is gone, and assuming so creates a race condition that 127 // can be exagerated by artifically slowing the FrameHostMsg_SwapOut_ACK reply 128 // from the renderer being navigated from. 129 content::RenderProcessHost* NavigateToURLWithDisposition( 130 Browser* browser, 131 const GURL& url, 132 WindowOpenDisposition disposition, 133 int browser_test_flags); 134 135 // Navigates the selected tab of |browser| to |url|, blocking until the 136 // number of navigations specified complete. 137 // 138 // Returns a RenderProcessHost* for the renderer where the navigation 139 // occured. Use this when navigating again, when the test wants to wait not 140 // just for the navigation to complete but also for the previous 141 // RenderProcessHost to be torn down. Navigation does NOT imply the old 142 // RenderProcessHost is gone, and assuming so creates a race condition that 143 // can be exagerated by artifically slowing the FrameHostMsg_SwapOut_ACK reply 144 // from the renderer being navigated from. 145 content::RenderProcessHost* NavigateToURLBlockUntilNavigationsComplete( 146 Browser* browser, 147 const GURL& url, 148 int number_of_navigations); 149 150 // Navigates the specified tab (via |disposition|) of |browser| to |url|, 151 // blocking until the |number_of_navigations| specified complete. 152 // |disposition| indicates what tab the download occurs in, and 153 // |browser_test_flags| controls what to wait for before continuing. 154 content::RenderProcessHost* 155 NavigateToURLWithDispositionBlockUntilNavigationsComplete( 156 Browser* browser, 157 const GURL& url, 158 int number_of_navigations, 159 WindowOpenDisposition disposition, 160 int browser_test_flags); 161 162 // Generate the file path for testing a particular test. 163 // The file for the tests is all located in 164 // test_root_directory/dir/<file> 165 // The returned path is base::FilePath format. 166 base::FilePath GetTestFilePath(const base::FilePath& dir, 167 const base::FilePath& file); 168 169 // Generate the URL for testing a particular test. 170 // HTML for the tests is all located in 171 // test_root_directory/dir/<file> 172 // The returned path is GURL format. 173 GURL GetTestUrl(const base::FilePath& dir, const base::FilePath& file); 174 175 // Generate the path of the build directory, relative to the source root. 176 bool GetRelativeBuildDirectory(base::FilePath* build_dir); 177 178 // Blocks until an application modal dialog is shown and returns it. 179 javascript_dialogs::AppModalDialogController* WaitForAppModalDialog(); 180 181 #if defined(TOOLKIT_VIEWS) 182 // Blocks until the given view attains the given visibility state. 183 void WaitForViewVisibility(Browser* browser, ViewID vid, bool visible); 184 #endif 185 186 // Performs a find in the page of the specified tab. Returns the number of 187 // matches found. |ordinal| is an optional parameter which is set to the index 188 // of the current match. |selection_rect| is an optional parameter which is set 189 // to the location of the current match. 190 int FindInPage(content::WebContents* tab, 191 const base::string16& search_string, 192 bool forward, 193 bool case_sensitive, 194 int* ordinal, 195 gfx::Rect* selection_rect); 196 197 // Blocks until the |history_service|'s history finishes loading. 198 void WaitForHistoryToLoad(history::HistoryService* history_service); 199 200 // Blocks until a Browser is added to the BrowserList. 201 Browser* WaitForBrowserToOpen(); 202 203 // Blocks until a Browser is removed from the BrowserList. If |browser| is null, 204 // the removal of any browser will suffice; otherwise the removed browser must 205 // match |browser|. 206 void WaitForBrowserToClose(Browser* browser = nullptr); 207 208 // Download the given file and waits for the download to complete. 209 void DownloadURL(Browser* browser, const GURL& download_url); 210 211 // Waits until the autocomplete controller reaches its done state. 212 void WaitForAutocompleteDone(Browser* browser); 213 214 // Send the given text to the omnibox and wait until it's updated. 215 void SendToOmniboxAndSubmit( 216 Browser* browser, 217 const std::string& input, 218 base::TimeTicks match_selection_timestamp = base::TimeTicks()); 219 220 // Gets the first browser that is not in the specified set. 221 Browser* GetBrowserNotInSet(const std::set<Browser*>& excluded_browsers); 222 223 // Gets the size and value of the cookie string for |url| in the given tab. 224 // Can be called from any thread. 225 void GetCookies(const GURL& url, 226 content::WebContents* contents, 227 int* value_size, 228 std::string* value); 229 230 // Similar to WindowedNotificationObserver but also provides a way of retrieving 231 // the details associated with the notification. 232 // Note that in order to use that class the details class should be copiable, 233 // which is the case with most notifications. 234 template <class U> 235 class WindowedNotificationObserverWithDetails 236 : public content::WindowedNotificationObserver { 237 public: WindowedNotificationObserverWithDetails(int notification_type,const content::NotificationSource & source)238 WindowedNotificationObserverWithDetails( 239 int notification_type, 240 const content::NotificationSource& source) 241 : content::WindowedNotificationObserver(notification_type, source) {} 242 WindowedNotificationObserverWithDetails( 243 const WindowedNotificationObserverWithDetails&) = delete; 244 WindowedNotificationObserverWithDetails& operator=( 245 const WindowedNotificationObserverWithDetails&) = delete; 246 247 // Fills |details| with the details of the notification received for |source|. GetDetailsFor(uintptr_t source,U * details)248 bool GetDetailsFor(uintptr_t source, U* details) { 249 typename std::map<uintptr_t, U>::const_iterator iter = 250 details_.find(source); 251 if (iter == details_.end()) 252 return false; 253 *details = iter->second; 254 return true; 255 } 256 Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)257 void Observe(int type, 258 const content::NotificationSource& source, 259 const content::NotificationDetails& details) override { 260 const U* details_ptr = content::Details<U>(details).ptr(); 261 if (details_ptr) 262 details_[source.map_key()] = *details_ptr; 263 content::WindowedNotificationObserver::Observe(type, source, details); 264 } 265 266 private: 267 std::map<uintptr_t, U> details_; 268 }; 269 270 // Notification observer which waits for navigation events and blocks until 271 // a specific URL is loaded. The URL must be an exact match. 272 class UrlLoadObserver : public content::WindowedNotificationObserver { 273 public: 274 // Register to listen for notifications of the given type from either a 275 // specific source, or from all sources if |source| is 276 // NotificationService::AllSources(). 277 UrlLoadObserver(const GURL& url, const content::NotificationSource& source); 278 UrlLoadObserver(const UrlLoadObserver&) = delete; 279 UrlLoadObserver& operator=(const UrlLoadObserver&) = delete; 280 ~UrlLoadObserver() override; 281 282 // content::NotificationObserver: 283 void Observe(int type, 284 const content::NotificationSource& source, 285 const content::NotificationDetails& details) override; 286 287 private: 288 GURL url_; 289 }; 290 291 // A helper that will wait until a tab is added to a specific Browser. 292 class TabAddedWaiter : public TabStripModelObserver { 293 public: 294 explicit TabAddedWaiter(Browser* browser); 295 TabAddedWaiter(const TabAddedWaiter&) = delete; 296 TabAddedWaiter& operator=(const TabAddedWaiter&) = delete; 297 ~TabAddedWaiter() override = default; 298 299 void Wait(); 300 301 // TabStripModelObserver: 302 void OnTabStripModelChanged( 303 TabStripModel* tab_strip_model, 304 const TabStripModelChange& change, 305 const TabStripSelectionChange& selection) override; 306 307 private: 308 base::RunLoop run_loop_; 309 }; 310 311 // Similar to TabAddedWaiter, but will observe tabs added to all Browser 312 // objects, and can return the last tab that was added. 313 class AllBrowserTabAddedWaiter : public TabStripModelObserver, 314 public BrowserListObserver { 315 public: 316 AllBrowserTabAddedWaiter(); 317 AllBrowserTabAddedWaiter(const AllBrowserTabAddedWaiter&) = delete; 318 AllBrowserTabAddedWaiter& operator=(const AllBrowserTabAddedWaiter&) = delete; 319 ~AllBrowserTabAddedWaiter() override; 320 321 content::WebContents* Wait(); 322 323 // TabStripModelObserver: 324 void OnTabStripModelChanged( 325 TabStripModel* tab_strip_model, 326 const TabStripModelChange& change, 327 const TabStripSelectionChange& selection) override; 328 329 // BrowserListObserver: 330 void OnBrowserAdded(Browser* browser) override; 331 332 private: 333 base::RunLoop run_loop_; 334 335 // The last tab that was added. 336 content::WebContents* web_contents_ = nullptr; 337 }; 338 339 // Enumerates all history contents on the backend thread. Returns them in 340 // descending order by time. 341 class HistoryEnumerator { 342 public: 343 explicit HistoryEnumerator(Profile* profile); 344 HistoryEnumerator(const HistoryEnumerator&) = delete; 345 HistoryEnumerator& operator=(const HistoryEnumerator&) = delete; 346 ~HistoryEnumerator(); 347 urls()348 std::vector<GURL>& urls() { return urls_; } 349 350 private: 351 std::vector<GURL> urls_; 352 }; 353 354 // In general, tests should use WaitForBrowserToClose() and 355 // WaitForBrowserToOpen() rather than instantiating this class directly. 356 class BrowserChangeObserver : public BrowserListObserver { 357 public: 358 enum class ChangeType { 359 kAdded, 360 kRemoved, 361 }; 362 363 BrowserChangeObserver(Browser* browser, ChangeType type); 364 BrowserChangeObserver(const BrowserChangeObserver&) = delete; 365 BrowserChangeObserver& operator=(const BrowserChangeObserver&) = delete; 366 ~BrowserChangeObserver() override; 367 368 Browser* Wait(); 369 370 // BrowserListObserver: 371 void OnBrowserAdded(Browser* browser) override; 372 373 void OnBrowserRemoved(Browser* browser) override; 374 375 private: 376 Browser* browser_; 377 ChangeType type_; 378 base::RunLoop run_loop_; 379 }; 380 381 } // namespace ui_test_utils 382 383 #endif // CHROME_TEST_BASE_UI_TEST_UTILS_H_ 384