chromium/chrome/test/base/ui_test_utils.h

// Copyright 2012 The Chromium Authors
// 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 <set>
#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/exclusive_access/fullscreen_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/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 "ui/views/view_observer.h"
#include "url/gurl.h"

#if defined(TOOLKIT_VIEWS)
#include "ui/views/test/widget_test_api.h"
#endif

class Browser;
class FullscreenController;
class Profile;

namespace javascript_dialogs {
class AppModalDialogController;
}

namespace base {
class FilePath;
}

struct NavigateParams;

namespace content {
class RenderFrameHost;
class WebContents;
}

namespace gfx {
class Rect;
}

namespace views {
class View;
}

// 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 {};

// 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);

// Waits until the window gets minimized.
// Returns success or not.
bool WaitForMinimized(Browser* browser);

// Waits until the window gets maximized.
// Returns success or not.
bool WaitForMaximized(Browser* browser);

// See comment on views::AsyncWidgetRequestWaiter.
[[nodiscard]] views::AsyncWidgetRequestWaiter CreateAsyncWidgetRequestWaiter(
    Browser& browser);

// SetAndWaitForBounds sets the given `bounds` on `browser` and waits until the
// bounds update will be observable from all parts of the client (on Wayland).
// This does not verify the resulting bounds.
void SetAndWaitForBounds(Browser& browser, const gfx::Rect& bounds);

// Maximizes the browser window and wait until the window is maximized and all
// related visible UI effects are applied and observable from chrome.
// Returns true if succeeded.
bool MaximizeAndWaitUntilUIUpdateDone(Browser& browser);

// Waits for fullscreen state to be updated.
// There're two variation of fullscreen concepts, browser fullscreen and
// tab fullscreen. Due to fullscreen implementation, fullscreen state may
// be updated synchronously, while observer invocations and some other
// following tasks are done asynchronously.
// This class checks the condition on instance creation, then every
// OnFullscreenStateChanged invocation to deal with the situation.
// Once the condition is met, this class remembers the state, so following
// Wait() will do nothing, even if the condition is changed once again.
class FullscreenWaiter : public FullscreenObserver {};

// This waiter waits for the specified |browser| becoming the last active
// browser in BrowserList. In Lacros, BrowserList::SetLastActive is triggered by
// OnWidgetActivationChanged when wayland notify the UI change asynchronously.
// Many testing code needs to wait until the expected browser to be set as
// the last active browser, and some testing code needs to wait until
// BrowserList::OnSetLastActive() is observed.
class BrowserSetLastActiveWaiter : public BrowserListObserver {};

// Toggles browser fullscreen mode, then wait for its completion.
void ToggleFullscreenModeAndWait(Browser* browser);

// Waits until |browser| becomes active.
void WaitUntilBrowserBecomeActive(Browser* browser);

// Returns true if |browser| is active.
bool IsBrowserActive(Browser* browser);

// Opens a new browser window with chrome::NewEmptyWindow() and wait until it
// becomes active.
// Returns newly created browser.
Browser* OpenNewEmptyWindowAndWaitUntilActivated(
    Profile* profile,
    bool should_trigger_session_restore = false);

// Waits for |browser| becomes the last active browser.
// By default, the waiting will be satisfied if the expected |browser| is the
// last active browser in BrowserList. In most cases, this is enough for the
// testing code depending on chrome::FindLastActive(). In some cases, for
// example, when there is only one browser in the BrowserList, |browser| can be
// returned as the last active browser even if the asynchronous Wayland UI event
// has not arrived yet (i.e. BrowserList::SetLastActive() is not triggered and
// the code observing BrowserList::OnSetLastActive() will not be called). If the
// test case depends on the code observing BrowserList::OnSetLastActive() being
// executed first, we can configure the waiter to be satisfied upon
// OnBrowserSetLastActive is observed by passing
// |wait_for_set_last_active_observed| being true.
// Note: The last active browser is not necessarily the current active browser.
// A browser could be de-activated and still the last active browser. In many
// tests, BrowserList::GetLastActive() is incorrectly used to verify the
// expected browser being the active browser, see b/345848530.
void WaitForBrowserSetLastActive(
    Browser* browser,
    bool wait_for_set_last_active_observed = false);

// 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);

// Utility class to watch all existing and added tabs, until some interesting
// thing has happened.  Subclasses get to decide what they consider to be
// interesting.  In practice, usage is like this:
//
// - Subclass `AllTabsObserver`
// - Override `ProcessOneWebContents()` to check for the interesting thing.
// - Optionally return a `WebContentsObserver` that will watch for the
//   interesting thing for this WebContents.
// - Eventually call `ConditionMet()` to indicate that the interesting thing has
//   happened, and no further waiting is needed.
//
// Users of this class just call `Wait()` at most once.
class AllTabsObserver : public TabStripModelObserver,
                        public BrowserListObserver {};

// Observer which waits for navigation events and blocks until a specific URL is
// loaded. The URL must be an exact match.
class UrlLoadObserver : public AllTabsObserver {};

// A helper that will wait until a tab is added to a specific Browser.
class TabAddedWaiter : public TabStripModelObserver {};

// 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 {};

// Enumerates all history contents on the backend thread. Returns them in
// descending order by time.
class HistoryEnumerator {};

// In general, tests should use WaitForBrowserToClose() and
// WaitForBrowserToOpen() rather than instantiating this class directly.
class BrowserChangeObserver : public BrowserListObserver {};

// Encapsulates waiting for the browser window to change state. This is
// needed for example on Chrome desktop linux, where window state change is done
// asynchronously as an event received from a different process.
class CheckWaiter {};

// Used to wait for the view to contain non-empty bounds.
class ViewBoundsWaiter : public views::ViewObserver {};

}  // namespace ui_test_utils

#endif  // CHROME_TEST_BASE_UI_TEST_UTILS_H_