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