| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_TEST_BASE_UI_TEST_UTILS_H_ |
| #define CHROME_TEST_BASE_UI_TEST_UTILS_H_ |
| |
| #include <map> |
| #include <queue> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "chrome/browser/ui/browser_list_observer.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" |
| #include "chrome/browser/ui/view_ids.h" |
| #include "components/history/core/browser/history_service.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/test/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/window_open_disposition.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "url/gurl.h" |
| |
| class Browser; |
| class Profile; |
| |
| namespace javascript_dialogs { |
| class AppModalDialogController; |
| } |
| |
| namespace base { |
| class FilePath; |
| } |
| |
| struct NavigateParams; |
| |
| namespace content { |
| class RenderFrameHost; |
| class WebContents; |
| } |
| |
| namespace gfx { |
| class Rect; |
| } |
| |
| // A collections of functions designed for use with InProcessBrowserTest. |
| namespace ui_test_utils { |
| |
| // Flags to indicate what to wait for in a navigation test. |
| // They can be ORed together. |
| // The order in which the waits happen when more than one is selected, is: |
| // Browser |
| // Tab |
| // Navigation |
| enum BrowserTestWaitFlags { |
| // Don't wait for anything. |
| BROWSER_TEST_NONE = 0, |
| // Wait for a new browser. |
| BROWSER_TEST_WAIT_FOR_BROWSER = 1 << 0, |
| // Wait for a new tab. |
| BROWSER_TEST_WAIT_FOR_TAB = 1 << 1, |
| // Wait for loading to stop. Loading stops when either |
| // a document and its subresources are completely loaded |
| // (i.e. the spinner has stopped) or no document can be |
| // loaded due to an e.g. an error or crash. |
| BROWSER_TEST_WAIT_FOR_LOAD_STOP = 1 << 2, |
| |
| BROWSER_TEST_MASK = BROWSER_TEST_WAIT_FOR_BROWSER | |
| BROWSER_TEST_WAIT_FOR_TAB | |
| BROWSER_TEST_WAIT_FOR_LOAD_STOP |
| }; |
| |
| // Puts the current tab title in |title|. Returns true on success. |
| bool GetCurrentTabTitle(const Browser* browser, std::u16string* title); |
| |
| // NavigateToURL* functions navigate the given |browser| to |url| according the |
| // provided parameters and block until ready (by default - until loading stops, |
| // see BROWSER_TEST_WAIT_FOR_LOAD_STOP for more details. Note that this is |
| // different from content::NavigateToURL, which block only until navigation |
| // succeeds or fails, which generally happens earlier). |
| // |
| // Some of these functions return RenderFrameHost* where the navigation was |
| // committed or nullptr if the navigation failed. The caller should inspect the |
| // return value - typically with: ASSERT_TRUE(NavigateToURL(...)). |
| // |
| // Note: if the navigation has committed, this doesn't mean that the old |
| // RenderFrameHost was destroyed: |
| // - it either can wait for the renderer process to finish running unload |
| // handlers and acknowledge that. |
| // - it can be stored in BackForwardCache to be reused for subsequent |
| // back/forward navigation. |
| // |
| // If the test needs to test RenderFrameHost cleanup, use |
| // BackForwardCache::DisableForTesting to ensure that RenderFrameHost isn't |
| // preserved in BackForwardCache and |
| // RenderFrameDeletedObserver::WaitUntilDeleted to wait for deletion. |
| |
| // Navigate according to |params|. |
| void NavigateToURL(NavigateParams* params); |
| |
| // Navigate current tab of the |browser| to |url| using POST request, simulating |
| // form submission. |
| void NavigateToURLWithPost(Browser* browser, const GURL& url); |
| |
| // Navigate current tab of the |browser| to |url|, simulating a user typing |
| // |url| into the omnibox. |
| [[nodiscard]] content::RenderFrameHost* NavigateToURL(Browser* browser, |
| const GURL& url); |
| |
| // Same as |NavigateToURL|, but: |
| // - |disposition| allows to specify in which tab navigation should happen |
| // - |browser_test_flags| allows to specify a different condition this function |
| // would wait until, see BrowserTestWaitFlags for details. |
| content::RenderFrameHost* NavigateToURLWithDisposition( |
| Browser* browser, |
| const GURL& url, |
| WindowOpenDisposition disposition, |
| int browser_test_flags); |
| |
| // Same as |NavigateToURL|, but wait for a given number of navigations to |
| // complete instead of the tab to finish loading. |
| content::RenderFrameHost* NavigateToURLBlockUntilNavigationsComplete( |
| Browser* browser, |
| const GURL& url, |
| int number_of_navigations); |
| |
| // See |NavigateToURLWithDisposition| and |
| // |NavigateToURLBlockUntilNavigationsComplete|. |
| content::RenderFrameHost* |
| NavigateToURLWithDispositionBlockUntilNavigationsComplete( |
| Browser* browser, |
| const GURL& url, |
| int number_of_navigations, |
| WindowOpenDisposition disposition, |
| int browser_test_flags); |
| |
| // Generate the file path for testing a particular test. |
| // The file for the tests is all located in |
| // test_root_directory/dir/<file> |
| // The returned path is base::FilePath format. |
| base::FilePath GetTestFilePath(const base::FilePath& dir, |
| const base::FilePath& file); |
| |
| // Generate the URL for testing a particular test. |
| // HTML for the tests is all located in |
| // test_root_directory/dir/<file> |
| // The returned path is GURL format. |
| GURL GetTestUrl(const base::FilePath& dir, const base::FilePath& file); |
| |
| // Generate the path of the build directory, relative to the source root. |
| bool GetRelativeBuildDirectory(base::FilePath* build_dir); |
| |
| // Blocks until an application modal dialog is shown and returns it. |
| javascript_dialogs::AppModalDialogController* WaitForAppModalDialog(); |
| |
| #if defined(TOOLKIT_VIEWS) |
| // Blocks until the given view attains the given visibility state. |
| void WaitForViewVisibility(Browser* browser, ViewID vid, bool visible); |
| #endif |
| |
| // Performs a find in the page of the specified tab. Returns the number of |
| // matches found. |ordinal| is an optional parameter which is set to the index |
| // of the current match. |selection_rect| is an optional parameter which is set |
| // to the location of the current match. |
| int FindInPage(content::WebContents* tab, |
| const std::u16string& search_string, |
| bool forward, |
| bool case_sensitive, |
| int* ordinal, |
| gfx::Rect* selection_rect); |
| |
| // Blocks until the |history_service|'s history finishes loading. |
| void WaitForHistoryToLoad(history::HistoryService* history_service); |
| |
| // Blocks until a Browser is added to the BrowserList. |
| Browser* WaitForBrowserToOpen(); |
| |
| // Blocks until a Browser is removed from the BrowserList. If |browser| is null, |
| // the removal of any browser will suffice; otherwise the removed browser must |
| // match |browser|. |
| void WaitForBrowserToClose(Browser* browser = nullptr); |
| |
| // Download the given file and waits for the download to complete. |
| void DownloadURL(Browser* browser, const GURL& download_url); |
| |
| // Waits until the autocomplete controller reaches its done state. |
| void WaitForAutocompleteDone(Browser* browser); |
| |
| // Send the given text to the omnibox and wait until it's updated. |
| void SendToOmniboxAndSubmit( |
| Browser* browser, |
| const std::string& input, |
| base::TimeTicks match_selection_timestamp = base::TimeTicks()); |
| |
| // Gets the first browser that is not in the specified set. |
| Browser* GetBrowserNotInSet(const std::set<Browser*>& excluded_browsers); |
| |
| // Gets the size and value of the cookie string for |url| in the given tab. |
| // Can be called from any thread. |
| void GetCookies(const GURL& url, |
| content::WebContents* contents, |
| int* value_size, |
| std::string* value); |
| |
| // Similar to WindowedNotificationObserver but also provides a way of retrieving |
| // the details associated with the notification. |
| // Note that in order to use that class the details class should be copiable, |
| // which is the case with most notifications. |
| template <class U> |
| class WindowedNotificationObserverWithDetails |
| : public content::WindowedNotificationObserver { |
| public: |
| WindowedNotificationObserverWithDetails( |
| int notification_type, |
| const content::NotificationSource& source) |
| : content::WindowedNotificationObserver(notification_type, source) {} |
| WindowedNotificationObserverWithDetails( |
| const WindowedNotificationObserverWithDetails&) = delete; |
| WindowedNotificationObserverWithDetails& operator=( |
| const WindowedNotificationObserverWithDetails&) = delete; |
| |
| // Fills |details| with the details of the notification received for |source|. |
| bool GetDetailsFor(uintptr_t source, U* details) { |
| typename std::map<uintptr_t, U>::const_iterator iter = |
| details_.find(source); |
| if (iter == details_.end()) |
| return false; |
| *details = iter->second; |
| return true; |
| } |
| |
| void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) override { |
| const U* details_ptr = content::Details<U>(details).ptr(); |
| if (details_ptr) |
| details_[source.map_key()] = *details_ptr; |
| content::WindowedNotificationObserver::Observe(type, source, details); |
| } |
| |
| private: |
| std::map<uintptr_t, U> details_; |
| }; |
| |
| // Notification observer which waits for navigation events and blocks until |
| // a specific URL is loaded. The URL must be an exact match. |
| class UrlLoadObserver : public content::WindowedNotificationObserver { |
| public: |
| // Register to listen for notifications of the given type from either a |
| // specific source, or from all sources if |source| is |
| // NotificationService::AllSources(). |
| UrlLoadObserver(const GURL& url, const content::NotificationSource& source); |
| UrlLoadObserver(const UrlLoadObserver&) = delete; |
| UrlLoadObserver& operator=(const UrlLoadObserver&) = delete; |
| ~UrlLoadObserver() override; |
| |
| // content::NotificationObserver: |
| void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) override; |
| |
| private: |
| GURL url_; |
| }; |
| |
| // A helper that will wait until a tab is added to a specific Browser. |
| class TabAddedWaiter : public TabStripModelObserver { |
| public: |
| explicit TabAddedWaiter(Browser* browser); |
| TabAddedWaiter(const TabAddedWaiter&) = delete; |
| TabAddedWaiter& operator=(const TabAddedWaiter&) = delete; |
| ~TabAddedWaiter() override = default; |
| |
| void Wait(); |
| |
| // TabStripModelObserver: |
| void OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) override; |
| |
| private: |
| base::RunLoop run_loop_; |
| }; |
| |
| // Similar to TabAddedWaiter, but will observe tabs added to all Browser |
| // objects, and can return the last tab that was added. |
| class AllBrowserTabAddedWaiter : public TabStripModelObserver, |
| public BrowserListObserver { |
| public: |
| AllBrowserTabAddedWaiter(); |
| AllBrowserTabAddedWaiter(const AllBrowserTabAddedWaiter&) = delete; |
| AllBrowserTabAddedWaiter& operator=(const AllBrowserTabAddedWaiter&) = delete; |
| ~AllBrowserTabAddedWaiter() override; |
| |
| content::WebContents* Wait(); |
| |
| // TabStripModelObserver: |
| void OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) override; |
| |
| // BrowserListObserver: |
| void OnBrowserAdded(Browser* browser) override; |
| |
| private: |
| base::RunLoop run_loop_; |
| |
| // The last tab that was added. |
| raw_ptr<content::WebContents> web_contents_ = nullptr; |
| }; |
| |
| // Enumerates all history contents on the backend thread. Returns them in |
| // descending order by time. |
| class HistoryEnumerator { |
| public: |
| explicit HistoryEnumerator(Profile* profile); |
| HistoryEnumerator(const HistoryEnumerator&) = delete; |
| HistoryEnumerator& operator=(const HistoryEnumerator&) = delete; |
| ~HistoryEnumerator(); |
| |
| std::vector<GURL>& urls() { return urls_; } |
| |
| private: |
| std::vector<GURL> urls_; |
| }; |
| |
| // In general, tests should use WaitForBrowserToClose() and |
| // WaitForBrowserToOpen() rather than instantiating this class directly. |
| class BrowserChangeObserver : public BrowserListObserver { |
| public: |
| enum class ChangeType { |
| kAdded, |
| kRemoved, |
| }; |
| |
| BrowserChangeObserver(Browser* browser, ChangeType type); |
| BrowserChangeObserver(const BrowserChangeObserver&) = delete; |
| BrowserChangeObserver& operator=(const BrowserChangeObserver&) = delete; |
| ~BrowserChangeObserver() override; |
| |
| Browser* Wait(); |
| |
| // BrowserListObserver: |
| void OnBrowserAdded(Browser* browser) override; |
| |
| void OnBrowserRemoved(Browser* browser) override; |
| |
| private: |
| raw_ptr<Browser> browser_; |
| ChangeType type_; |
| base::RunLoop run_loop_; |
| }; |
| |
| } // namespace ui_test_utils |
| |
| #endif // CHROME_TEST_BASE_UI_TEST_UTILS_H_ |