chromium/content/public/test/browser_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 CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
#define CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_

#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/json/json_writer.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/types/strong_alias.h"
#include "base/types/to_address.h"
#include "build/build_config.h"
#include "cc/test/pixel_test_utils.h"
#include "content/public/browser/commit_deferring_condition.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_metadata_provider.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/common/page_type.h"
#include "content/public/test/test_utils.h"
#include "ipc/message_filter.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/base/load_flags.h"
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_partition_key_collection.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/cookie_manager.mojom-forward.h"
#include "storage/common/file_system/file_system_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-test-utils.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
#include "third_party/blink/public/mojom/keyboard_lock/keyboard_lock.mojom-shared.h"
#include "third_party/blink/public/mojom/navigation/navigation_params.mojom-shared.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/display/display_switches.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/types/event_type.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_handle.h"
#endif

namespace gfx {
class Point;
}  // namespace gfx

namespace net {
class CanonicalCookie;
namespace test_server {
class EmbeddedTestServer;
}  // namespace test_server

// TODO(svaldez): Remove typedef once EmbeddedTestServer has been migrated
// out of net::test_server.
EmbeddedTestServer;
}  // namespace net

namespace ui {
class AXPlatformNodeDelegate;
class AXTreeID;
}  // namespace ui

#if BUILDFLAG(IS_WIN)
namespace Microsoft {
namespace WRL {
template <typename>
class ComPtr;
}  // namespace WRL
}  // namespace Microsoft

typedef int PROPERTYID;
#endif

// A collections of functions designed for use with content_browsertests and
// browser_tests.
// TO BE CLEAR: any function here must work against both binaries. If it only
// works with browser_tests, it should be in chrome\test\base\ui_test_utils.h.
// If it only works with content_browsertests, it should be in
// content\test\content_browser_test_utils.h.

namespace blink {
class StorageKey;
struct TransferableMessage;

namespace mojom {
class FrameWidget;
}  // namespace mojom

}  // namespace blink

namespace storage {
class BlobUrlRegistry;
}

namespace content {

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
class MockCapturedSurfaceController;
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

#if defined(USE_AURA)
class SelectionBoundsWaiter;
#endif  // defined(USE_AURA)

class BrowserContext;
class FileSystemAccessPermissionContext;
class FrameTreeNode;
class NavigationHandle;
class NavigationRequest;
class RenderFrameMetadataProviderImpl;
class RenderFrameProxyHost;
class RenderWidgetHost;
class RenderWidgetHostImpl;
class RenderWidgetHostView;
class ScopedAllowRendererCrashes;
class ToRenderFrameHost;
class WebContents;

// This encapsulates the pattern of waiting for an event and returning whether
// that event was received from `Wait`. This makes it easy to do the right thing
// in Wait, i.e. return with `[[nodiscard]]`.
class WaiterHelper {};

// Navigates |web_contents| to |url|, blocking until the navigation finishes.
// Returns true if the page was loaded successfully and the last committed URL
// matches |url|.  This is a browser-initiated navigation that simulates a user
// typing |url| into the address bar.
[[nodiscard]] bool NavigateToURL(WebContents* web_contents, const GURL& url);

// Same as above, but takes in an additional URL, |expected_commit_url|, to
// which the navigation should eventually commit.  This is useful for cases
// like redirects, where navigation starts on one URL but ends up committing a
// different URL.  This function will return true if navigating to |url|
// results in a successful commit to |expected_commit_url|.
[[nodiscard]] bool NavigateToURL(WebContents* web_contents,
                                 const GURL& url,
                                 const GURL& expected_commit_url);

// Navigates |web_contents| to |url|, blocking until the given number of
// navigations finishes. If |ignore_uncommitted_navigations| is true, then an
// aborted navigation also counts toward |number_of_navigations| being complete.
void NavigateToURLBlockUntilNavigationsComplete(
    WebContents* web_contents,
    const GURL& url,
    int number_of_navigations,
    bool ignore_uncommitted_navigations = true);
// Same, but allows specifying the full LoadURLParams instead of just the URL.
void NavigateToURLBlockUntilNavigationsComplete(
    WebContents* web_contents,
    const NavigationController::LoadURLParams& params,
    int number_of_navigations,
    bool ignore_uncommitted_navigations = true);

// Helpers for performing renderer-initiated navigations. Note these helpers are
// only suitable when the navigation is expected to at least start successfully,
// i.e. result in a `DidStartNavigation()` notification.
//
// To write a test where the renderer itself blocks or cancels the navigation,
// use `ExecJs()` or `EvalJs()`, e.g.:
//
//   EXPECT_THAT(ExecJs("try { location = ''; } catch (e) { e.message; }")
//                   .ExtractString(),
//               HasSubStr("..."));
//
// To write a test where the navigation results in a bad message kill, use
// `ExecuteScriptAsync()` + `RenderProcessHostBadMojoMessageWaiter`, e.g.:
//
//   ExecuteScriptAsync(rfh, JsReplace("location = $1", "/title2.html"));
//   RenderProcessHostBadMojoMessageWaiter kill_waiter(rfh->GetProcess());
//   EXPECT_THAT(kill_waiter.Wait(), Optional(HasSubstr("...")));

// Perform a renderer-initiated navigation of the frame |adapter| to |url|,
// blocking until the navigation finishes. The navigation is done by assigning
// location.href in the frame |adapter|. Returns true if the page was loaded
// successfully and the last committed URL matches |url|.
[[nodiscard]] bool NavigateToURLFromRenderer(const ToRenderFrameHost& adapter,
                                             const GURL& url);
// Similar to above but takes in an additional URL, |expected_commit_url|, to
// which the navigation should eventually commit. (See the browser-initiated
// counterpart for more details).
[[nodiscard]] bool NavigateToURLFromRenderer(const ToRenderFrameHost& adapter,
                                             const GURL& url,
                                             const GURL& expected_commit_url);

// Similar to the two helpers above, but perform the renderer-initiated
// navigation without a user gesture.
[[nodiscard]] bool NavigateToURLFromRendererWithoutUserGesture(
    const ToRenderFrameHost& adapter,
    const GURL& url);

[[nodiscard]] bool NavigateToURLFromRendererWithoutUserGesture(
    const ToRenderFrameHost& adapter,
    const GURL& url,
    const GURL& expected_commit_url);

// Perform a renderer-initiated navigation of the frame `adapter` to `url`.
// Returns true if the navigation started successfully and false otherwise.
[[nodiscard]] bool BeginNavigateToURLFromRenderer(
    const ToRenderFrameHost& adapter,
    const GURL& url);

// Navigate a frame with ID |iframe_id| to |url|, blocking until the navigation
// finishes.  Uses a renderer-initiated navigation from script code in the
// main frame.
//
// This method does not trigger a user activation before the navigation.  If
// necessary, a user activation can be triggered right before calling this
// method, e.g. by calling |ExecJs(frame_tree_node, "")|.
bool NavigateIframeToURL(WebContents* web_contents,
                         std::string_view iframe_id,
                         const GURL& url);

// Similar to |NavigateIframeToURL()| but returns as soon as the navigation is
// initiated.
bool BeginNavigateIframeToURL(WebContents* web_contents,
                              std::string_view iframe_id,
                              const GURL& url);

// Generate a URL for a file path including a query string.
GURL GetFileUrlWithQuery(const base::FilePath& path,
                         std::string_view query_string);

// Checks whether the page type of the last committed navigation entry matches
// |page_type|.
bool IsLastCommittedEntryOfPageType(WebContents* web_contents,
                                    content::PageType page_type);

// Waits for |web_contents| to stop loading.  If |web_contents| is not loading
// returns immediately.  Tests should use WaitForLoadStop instead and check that
// last navigation succeeds, and this function should only be used if the
// navigation leads to web_contents being destroyed.
void WaitForLoadStopWithoutSuccessCheck(WebContents* web_contents);

// Waits for |web_contents| to stop loading.  If |web_contents| is not loading
// returns immediately.  Returns true if the last navigation succeeded (resulted
// in a committed navigation entry of type PAGE_TYPE_NORMAL).
// TODO(alexmos): tests that use this function to wait for successful
// navigations should be refactored to do EXPECT_TRUE(WaitForLoadStop()).
bool WaitForLoadStop(WebContents* web_contents);

// If a test uses a beforeunload dialog, it must be prepared to avoid flakes.
// This function collects everything that needs to be done, except for user
// activation which is triggered only when |trigger_user_activation| is true.
// Note that beforeunload dialog attempts are ignored unless the frame has
// received a user activation.
void PrepContentsForBeforeUnloadTest(WebContents* web_contents,
                                     bool trigger_user_activation = true);

#if defined(USE_AURA) || BUILDFLAG(IS_ANDROID)
// If WebContent's view is currently being resized, this will wait for the ack
// from the renderer that the resize is complete and for the
// WindowEventDispatcher to release the pointer moves. If there's no resize in
// progress, the method will return right away.
void WaitForResizeComplete(WebContents* web_contents);
#endif  // defined(USE_AURA) || BUILDFLAG(IS_ANDROID)

void NotifyCopyableViewInWebContents(WebContents* web_contents,
                                     base::OnceClosure done_callback);
void NotifyCopyableViewInFrame(RenderFrameHost* render_frame_host,
                               base::OnceClosure done_callback);

// Allows tests to set the last committed origin of |render_frame_host|, to
// simulate a scenario that might happen with a compromised renderer or might
// not otherwise be possible.
void OverrideLastCommittedOrigin(RenderFrameHost* render_frame_host,
                                 const url::Origin& origin);

// Causes the specified web_contents to crash. Blocks until it is crashed.
void CrashTab(WebContents* web_contents);

// Sets up a commit interceptor to alter commits for |target_url| to change
// their commit URL to |new_url| and origin to |new_origin|. This will happen
// for all commits in |web_contents|.
void PwnCommitIPC(WebContents* web_contents,
                  const GURL& target_url,
                  const GURL& new_url,
                  const url::Origin& new_origin);

// Test helper to check the content-internal CanCommitURL() method on
// ChildProcessSecurityPolicy, determining whether a particular process is
// allowed to commit a navigation to `url`.
bool CanCommitURLForTesting(int child_id, const GURL& url);

// Causes the specified web_contents to issue an OnUnresponsiveRenderer event
// to its observers.
void SimulateUnresponsiveRenderer(WebContents* web_contents,
                                  RenderWidgetHost* widget);

// Simulates clicking at the center of the given tab asynchronously; modifiers
// may contain bits from WebInputEvent::Modifiers. Sends the event through
// RenderWidgetHostInputEventRouter and thus can target OOPIFs. If an OOPIF is
// the intended target, ensure that its hit test data is available for routing,
// using `WaitForHitTestData`, first.
// Note: For simulating clicks inside a fenced frame tree, this function does
// not work. Use `SimulateClickInFencedFrameTree` in
// `content/public/test/fenced_frame_test_util.cc`
void SimulateMouseClick(WebContents* web_contents,
                        int modifiers,
                        blink::WebMouseEvent::Button button);

// Simulates clicking at the point |point| of the given tab asynchronously;
// modifiers may contain bits from WebInputEvent::Modifiers. Sends the event
// through RenderWidgetHostInputEventRouter and thus can target OOPIFs. If an
// OOPIF is the intended target, ensure that its hit test data is available for
// routing, using `WaitForHitTestData`, first.
// Note: For simulating clicks inside a fenced frame tree, this function does
// not work. Use `SimulateClickInFencedFrameTree` in
// `content/public/test/fenced_frame_test_util.cc`
void SimulateMouseClickAt(WebContents* web_contents,
                          int modifiers,
                          blink::WebMouseEvent::Button button,
                          const gfx::Point& point);

// Retrieves the center coordinates of the element with id |id|.
// ATTENTION: When using these coordinates to simulate a click or tap make sure
// that the viewport is not zoomed as the coordinates returned by this method
// are relative to the page not the viewport. In particular for Android make
// sure the page has the meta tag
// <meta name="viewport" content="width=device-width,minimum-scale=1">
// TODO(crbug.com/40177926): Make the Simulate* methods more user
// friendly by taking zooming into account.
gfx::PointF GetCenterCoordinatesOfElementWithId(
    const ToRenderFrameHost& adapter,
    std::string_view id);

// Retrieves the center coordinates of the element with id |id| and simulates a
// mouse click there using SimulateMouseClickAt().
void SimulateMouseClickOrTapElementWithId(content::WebContents* web_contents,
                                          std::string_view id);

// Simulates asynchronously a mouse enter/move/leave event. The mouse event is
// routed through RenderWidgetHostInputEventRouter and thus can target OOPIFs.
void SimulateMouseEvent(WebContents* web_contents,
                        blink::WebInputEvent::Type type,
                        const gfx::Point& point);
void SimulateMouseEvent(WebContents* web_contents,
                        blink::WebInputEvent::Type type,
                        blink::WebMouseEvent::Button button,
                        const gfx::Point& point);

// Simulate a mouse wheel event.
void SimulateMouseWheelEvent(WebContents* web_contents,
                             const gfx::Point& point,
                             const gfx::Vector2d& delta,
                             const blink::WebMouseWheelEvent::Phase phase);

#if !BUILDFLAG(IS_MAC)
// Simulate a mouse wheel event with the ctrl modifier set.
void SimulateMouseWheelCtrlZoomEvent(RenderWidgetHost* render_widget_host,
                                     const gfx::Point& point,
                                     bool zoom_in,
                                     blink::WebMouseWheelEvent::Phase phase);

void SimulateTouchscreenPinch(WebContents* web_contents,
                              const gfx::PointF& anchor,
                              float scale_change,
                              base::OnceClosure on_complete);

#endif  // !BUILDFLAG(IS_MAC)

// Sends a GesturePinch Begin/Update/End sequence.
void SimulateGesturePinchSequence(RenderWidgetHost* render_widget_host,
                                  const gfx::Point& point,
                                  float scale,
                                  blink::WebGestureDevice source_device);

void SimulateGesturePinchSequence(WebContents* web_contents,
                                  const gfx::Point& point,
                                  float scale,
                                  blink::WebGestureDevice source_device);

// Sends a simple, three-event (Begin/Update/End) gesture scroll.
void SimulateGestureScrollSequence(RenderWidgetHost* render_widget_host,
                                   const gfx::Point& point,
                                   const gfx::Vector2dF& delta);

void SimulateGestureScrollSequence(WebContents* web_contents,
                                   const gfx::Point& point,
                                   const gfx::Vector2dF& delta);

void SimulateGestureEvent(RenderWidgetHost* render_widget_host,
                          const blink::WebGestureEvent& gesture_event,
                          const ui::LatencyInfo& latency);

void SimulateGestureEvent(WebContents* web_contents,
                          const blink::WebGestureEvent& gesture_event,
                          const ui::LatencyInfo& latency);

// Taps the screen at |point|, using gesture Tap or TapDown.
void SimulateTapAt(WebContents* web_contents, const gfx::Point& point);
void SimulateTapDownAt(WebContents* web_contents, const gfx::Point& point);

// A helper function for SimulateTap(Down)At.
void SimulateTouchGestureAt(WebContents* web_contents,
                            const gfx::Point& point,
                            blink::WebInputEvent::Type type);

#if defined(USE_AURA)
// Generates a TouchEvent of |event_type| at |point|.
void SimulateTouchEventAt(WebContents* web_contents,
                          ui::EventType event_type,
                          const gfx::Point& point);

void SimulateLongTapAt(WebContents* web_contents, const gfx::Point& point);

// Can be used to wait for the caret bounds associated with `web_contents` to
// have non-zero size.
class NonZeroCaretSizeWaiter {};

// Can be used to wait for an update to the caret bounds associated with
// `web_contents`.
class CaretBoundsUpdateWaiter {};

// Can be used to wait for updates to the bounding box (i.e. the rectangle
// enclosing the selection region) associated with `web_contents`.
class BoundingBoxUpdateWaiter {};
#endif

// Taps the screen with modifires at |point|.
void SimulateTapWithModifiersAt(WebContents* web_contents,
                                unsigned Modifiers,
                                const gfx::Point& point);

// Sends a key press asynchronously.
// |key| specifies the UIEvents (aka: DOM4Events) value of the key.
// |code| specifies the UIEvents (aka: DOM4Events) value of the physical key.
// |key_code| alone is good enough for scenarios that only need the char
// value represented by a key event and not the physical key on the keyboard
// or the keyboard layout.
// If set to true, the modifiers |control|, |shift|, |alt|, and |command| are
// pressed down first before the key event, and released after.
void SimulateKeyPress(WebContents* web_contents,
                      ui::DomKey key,
                      ui::DomCode code,
                      ui::KeyboardCode key_code,
                      bool control,
                      bool shift,
                      bool alt,
                      bool command);

// Like SimulateKeyPress(), but does not send the char (AKA keypress) event.
// This is useful for arrow keys and other key presses that do not generate
// characters.
void SimulateKeyPressWithoutChar(WebContents* web_contents,
                                 ui::DomKey key,
                                 ui::DomCode code,
                                 ui::KeyboardCode key_code,
                                 bool control,
                                 bool shift,
                                 bool alt,
                                 bool command);

// Simulates `source_render_frame_host` sending `message` to
// `target_render_frame_host` through a `RenderFrameProxyHost`. This allows
// testing corner cases where postMessage() should not be allowed, even from a
// compromised renderer. `target_render_frame_host`'s frame must have a
// `RenderFrameProxyHost` in `source_render_frame_host`'s `SiteInstanceGroup`.
void SimulateProxyHostPostMessage(RenderFrameHost* source_render_frame_host,
                                  RenderFrameHost* target_render_frame_host,
                                  blink::TransferableMessage message);

// Reset touch action for the embedder of a BrowserPluginGuest.
void ResetTouchAction(RenderWidgetHost* host);

// Spins a run loop until effects of previously forwarded input are fully
// realized.
void RunUntilInputProcessed(RenderWidgetHost* host);

// Returns a string representation of a given |referrer_policy|. This is used to
// setup <meta name=referrer> tags in documents used for referrer-policy-based
// tests. The value `no-meta` indicates no tag should be created.
std::string ReferrerPolicyToString(
    network::mojom::ReferrerPolicy referrer_policy);

// For testing, bind FakeFrameWidget to a RenderWidgetHost associated
// with a given RenderFrameHost
mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
BindFakeFrameWidgetInterfaces(RenderFrameHost* frame);

// Set |active| state for a RenderWidgetHost associated with a given
// RenderFrameHost
void SimulateActiveStateForWidget(RenderFrameHost* frame, bool active);

// Return the value set for VisitedLinkSalt in the navigation's commit_params.
std::optional<uint64_t> GetVisitedLinkSaltForNavigation(
    NavigationHandle* navigation_handle);

// Holds down modifier keys for the duration of its lifetime and releases them
// upon destruction. This allows simulating multiple input events without
// simulating modifier key releases in between.
class ScopedSimulateModifierKeyPress {};

// Method to check what devices we have on the system.
bool IsWebcamAvailableOnSystem(WebContents* web_contents);

// Allow ExecJs/EvalJs methods to target either a WebContents or a
// RenderFrameHost.  Targeting a WebContents means executing the script in the
// RenderFrameHost returned by WebContents::GetPrimaryMainFrame(), which is the
// main frame.  Pass a specific RenderFrameHost to target it. Embedders may
// declare additional ConvertToRenderFrameHost functions for convenience.
class ToRenderFrameHost {};

RenderFrameHost* ConvertToRenderFrameHost(RenderFrameHost* render_view_host);
RenderFrameHost* ConvertToRenderFrameHost(WebContents* web_contents);

// Executes the passed |script| in the specified frame with a user gesture,
// without waiting for |script| completion.
//
// See also:
// - ExecJs (if you want to wait for script completion, or detect syntax errors)
// - EvalJs (if you want to retrieve a value)
// - DOMMessageQueue (to manually wait for domAutomationController.send(...))
void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
                        std::string_view script);

// Same as `content::ExecuteScriptAsync()`, but doesn't send a user gesture to
// the renderer.
void ExecuteScriptAsyncWithoutUserGesture(const ToRenderFrameHost& adapter,
                                          std::string_view script);

// JsLiteralHelper is a helper class that determines what types are legal to
// pass to StringifyJsLiteral. Legal types include int, string,
// std::string_view, char*, bool, double, GURL, url::Origin, and base::Value&&.
template <typename T>
struct JsLiteralHelper {};

// Specialization allowing GURL to be passed to StringifyJsLiteral.
template <>
struct JsLiteralHelper<GURL> {};

// Specialization allowing url::Origin to be passed to StringifyJsLiteral.
template <>
struct JsLiteralHelper<url::Origin> {};

// Construct a list-type base::Value from a mix of arguments.
//
// Each |arg| can be any type explicitly convertible to base::Value
// (including int/string/std::string_view/char*/double/bool), or any type that
// JsLiteralHelper is specialized for -- like URL and url::Origin, which emit
// string literals. |args| can be a mix of different types.
template <typename... Args>
base::Value ListValueOf(Args&&... args) {}

// Replaces $1, $2, $3, ..., $9 in |script_template| with JS literal values
// constructed from |args|, similar to base::ReplaceStringPlaceholders. Note
// that $10 and above aren't allowed.
//
// Unlike StringPrintf or manual concatenation, this version will properly
// escape string content, even if it contains slashes or quotation marks.
//
// Each |arg| can be any type explicitly convertible to base::Value
// (including int/string/std::string_view/char*/double/bool), or any type that
// JsLiteralHelper is specialized for -- like URL and url::Origin, which emit
// string literals. |args| can be a mix of different types.
//
// Example 1:
//
//   GURL page_url("http://example.com");
//   EXPECT_TRUE(ExecJs(
//       shell(), JsReplace("window.open($1, '_blank');", page_url)));
//
// $1 is replaced with a double-quoted JS string literal:
// "http://example.com". Note that quotes around $1 are not required.
//
// Example 2:
//
//   bool forced_reload = true;
//   EXPECT_TRUE(ExecJs(
//       shell(), JsReplace("window.location.reload($1);", forced_reload)));
//
// This becomes "window.location.reload(true);" -- because bool values are
// supported by base::Value. Numbers, lists, and dicts also work.
template <typename... Args>
std::string JsReplace(std::string_view script_template, Args&&... args) {}

// The return value of EvalJs. Captures the value (or the error) arising from
// script execution. When used with gtest assertions, EvalJsResult generally
// behaves like its wrapped value.
//
// An EvalJsResult can be consumed in two ways:
//
//  (1) [preferred] Pass it directly to an EXPECT_EQ() macro. It has
//      overloaded operator== against std::string, bool, int, double,
//      nullptr_t, and base::Value. This will produce readable assertion
//      failures if there is a type mismatch, or if an exception was thrown --
//      errors are never equal to anything.
//
//      For boolean results, note that EXPECT_TRUE(..) and EXPECT_FALSE()
//      won't compile; use EXPECT_EQ(true, ...) instead. This is intentional,
//      since EXPECT_TRUE() could be read ambiguously as either "expect
//      successful execution", "expect truthy value of any type", or "expect
//      boolean value 'true'".
//
//  (2) [use when necessary] Extract the underlying value of an expected type,
//      by calling ExtractString(), ExtractInt(), etc. This will produce a
//      CHECK failure if the execution didn't result in the appropriate type
//      of result, or if an exception was thrown.
struct EvalJsResult {};

// Enables EvalJsResult to be used directly in ASSERT/EXPECT macros:
//
//    ASSERT_EQ("ab", EvalJs(rfh, "'a' + 'b'"))
//    ASSERT_EQ(2, EvalJs(rfh, "1 + 1"))
//    ASSERT_EQ(nullptr, EvalJs(rfh, "var a = 1 + 1"))
//
// Error values never return true for any comparison operator.
template <typename T>
bool operator==(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator==(const EvalJsResult& a, const T& b) {}

template <typename T>
bool operator!=(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator!=(const EvalJsResult& a, const T& b) {}

template <typename T>
bool operator>=(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator>=(const EvalJsResult& a, const T& b) {}

template <typename T>
bool operator<=(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator<=(const EvalJsResult& a, const T& b) {}

template <typename T>
bool operator<(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator<(const EvalJsResult& a, const T& b) {}

template <typename T>
bool operator>(const T& a, const EvalJsResult& b) {}
template <typename T>
bool operator>(const EvalJsResult& a, const T& b) {}

inline bool operator==(std::nullptr_t a, const EvalJsResult& b) {}
template <typename T>
inline bool operator==(const EvalJsResult& a, std::nullptr_t b) {}

// Provides informative failure messages when the result of EvalJs() is
// used in a failing ASSERT_EQ or EXPECT_EQ.
std::ostream& operator<<(std::ostream& os, const EvalJsResult& bar);

enum EvalJsOptions {};

// EvalJs() -- run |script| in |execution_target| and return its value or error.
//
// Example simple usage:
//
//   EXPECT_EQ("https://abcd.com", EvalJs(render_frame_host, "self.origin"));
//   EXPECT_EQ(5, EvalJs(render_frame_host, "history.length"));
//   EXPECT_EQ(false, EvalJs(render_frame_host, "history.length > 5"));
//
// The result value of |script| is its "statement completion value" -- the same
// semantics used by Javascript's own eval() function. If |script|
// raises exceptions, or is syntactically invalid, an error is captured instead,
// including a full stack trace.
//
// The return value of EvalJs() may be used directly in EXPECT_EQ()
// macros, and compared for against std::string, int, or any other type for
// which base::Value has a constructor.  If an error was thrown by the script,
// any comparison operators will always return false.
//
// If |script|'s captured completion value is a Promise, this function blocks
// until the Promise is resolved. This enables a usage pattern where |script|
// may call an async function, and use the await keyword to wait for
// events to fire. For example:
//
//   EXPECT_EQ(200, EvalJs(rfh, "(async () => { var resp = (await fetch(url));"
//                              "               return resp.status; })()");
//
// In the above example, the immediately-invoked function expression results in
// a Promise (that's what async functions do); EvalJs will continue blocking
// until the Promise resolves, which happens when the async function returns
// the HTTP status code -- which is expected, in this case, to be 200.
//
//  - If possible, pass the result of EvalJs() into the second argument of an
//    EXPECT_EQ macro. This will trigger failure (and a nice message) if an
//    error occurs.
//  - JS exceptions are reliably captured and will appear as C++ assertion
//    failures.
//  - JS stack traces arising from exceptions are annotated with the
//    corresponding source code; this also appears in C++ assertion failures.
//  - Delayed response is supported via Promises and JS async/await.
//  - |script| doesn't need to call domAutomationController.send directly.
//  - When a script doesn't produce a result, it's likely an assertion
//    failure rather than a hang.  Doesn't get confused by crosstalk with
//    callers of domAutomationController.send() -- EvalJs does not rely on
//    domAutomationController.
//  - Lists, dicts, null values, etc. can be returned as base::Values.
//  - |after_script_invoke| is an optional callback which will be invoked after
//    script execution has started in the renderer but before the RunLoop is
//    blocked on the result.
//
// It is guaranteed that EvalJs works even when the target frame is frozen.
[[nodiscard]] EvalJsResult EvalJs(
    const ToRenderFrameHost& execution_target,
    std::string_view script,
    int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
    int32_t world_id = ISOLATED_WORLD_ID_GLOBAL,
    base::OnceClosure after_script_invoke = base::DoNothing());

// Like EvalJs(), but runs |raf_script| inside a requestAnimationFrame handler,
// and runs |script| after the rendering update has completed. By the time
// this method returns, any IPCs sent from the renderer process to the browser
// process during the lifecycle update should already have been received and
// processed by the browser.
[[nodiscard]] EvalJsResult EvalJsAfterLifecycleUpdate(
    const ToRenderFrameHost& execution_target,
    std::string_view raf_script,
    std::string_view script,
    int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
    int32_t world_id = ISOLATED_WORLD_ID_GLOBAL);

// Run a script exactly the same as EvalJs(), but ignore the resulting value.
//
// Returns AssertionSuccess() if |script| ran successfully, and
// AssertionFailure() if |script| contained a syntax error or threw an
// exception.
//
// As with EvalJs(), if the script passed evaluates to a Promise, this waits
// until it resolves (by default).
[[nodiscard]] ::testing::AssertionResult ExecJs(
    const ToRenderFrameHost& execution_target,
    std::string_view script,
    int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
    int32_t world_id = ISOLATED_WORLD_ID_GLOBAL);

// Walks the frame tree of the specified `page`, also descending into any inner
// frame-trees (e.g. GuestView), and returns the sole frame that matches the
// specified predicate function. Returns nullptr if no frame matches.
// EXPECTs that at most one frame matches.
RenderFrameHost* FrameMatchingPredicateOrNullptr(
    Page& page,
    base::RepeatingCallback<bool(RenderFrameHost*)> predicate);

// Same like FrameMatchingPredicateOrNullptr(), but EXPECTs that exactly one
// frame matches.
RenderFrameHost* FrameMatchingPredicate(
    Page& page,
    base::RepeatingCallback<bool(RenderFrameHost*)> predicate);

// Predicates for use with FrameMatchingPredicate[OrNullPtr]().
bool FrameMatchesName(std::string_view name, RenderFrameHost* frame);
bool FrameIsChildOfMainFrame(RenderFrameHost* frame);
bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame);

// Finds the child frame at the specified |index| for |adapter| and returns its
// RenderFrameHost.  Returns nullptr if such child frame does not exist.
RenderFrameHost* ChildFrameAt(const ToRenderFrameHost& adapter, size_t index);

// Returns true if |frame| has origin-keyed process isolation due to the
// OriginAgentCluster header.
bool HasOriginKeyedProcess(RenderFrameHost* frame);

// Returns true if `frame` has a sandboxed SiteInstance.
bool HasSandboxedSiteInstance(RenderFrameHost* frame);

// Returns the frames visited by |RenderFrameHost::ForEachRenderFrameHost| in
// the same order.
std::vector<RenderFrameHost*> CollectAllRenderFrameHosts(
    RenderFrameHost* starting_rfh);
// Returns the frames visited by |RenderFrameHost::ForEachRenderFrameHost| on
// |page|'s main document in the same order.
std::vector<RenderFrameHost*> CollectAllRenderFrameHosts(Page& page);
// Returns the frames visited by |WebContents::ForEachRenderFrameHost| in
// the same order.
std::vector<RenderFrameHost*> CollectAllRenderFrameHosts(
    WebContents* web_contents);

// Returns all WebContents. Note that this includes WebContents from any
// BrowserContext.
std::vector<WebContents*> GetAllWebContents();

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Executes the WebUI resource tests. Injects the test runner script prior to
// executing the tests.
//
// Returns true if tests ran successfully, false otherwise.
bool ExecuteWebUIResourceTest(WebContents* web_contents);
#endif

// Returns the serialized cookie string for the given url. Uses an inclusive
// SameSiteCookieContext by default, which gets cookies regardless of their
// SameSite attribute.
std::string GetCookies(
    BrowserContext* browser_context,
    const GURL& url,
    net::CookieOptions::SameSiteCookieContext context =
        net::CookieOptions::SameSiteCookieContext::MakeInclusive(),
    net::CookiePartitionKeyCollection key_collection =
        net::CookiePartitionKeyCollection::ContainsAll());

// Returns the canonical cookies for the given url.
std::vector<net::CanonicalCookie> GetCanonicalCookies(
    BrowserContext* browser_context,
    const GURL& url,
    net::CookiePartitionKeyCollection key_collection =
        net::CookiePartitionKeyCollection::ContainsAll());

// Sets a cookie for the given url. Uses inclusive SameSiteCookieContext by
// default, which gets cookies regardless of their SameSite attribute. The
// cookie is unpartitioned by default. Returns true on success.
bool SetCookie(BrowserContext* browser_context,
               const GURL& url,
               const std::string& value,
               net::CookieOptions::SameSiteCookieContext context =
                   net::CookieOptions::SameSiteCookieContext::MakeInclusive(),
               net::CookiePartitionKey* cookie_partition_key = nullptr);

// Deletes cookies matching the provided filter. Returns the number of cookies
// that were deleted.
uint32_t DeleteCookies(BrowserContext* browser_context,
                       network::mojom::CookieDeletionFilter filter);

// Fetches the histograms data from other processes.
//
// This function should be called after a child process has logged the
// histogram/metric being tested, to ensure that base::HistogramTester sees all
// the data from the child process.
//
// The caller should ensure that there is no race between 1) the call to
// FetchHistogramsFromChildProcesses() and 2) the child process shutting down.
// See also https://crbug.com/1246137 which describes how this is a test-only
// problem.
void FetchHistogramsFromChildProcesses();

// Registers a request handler which redirects to a different host, based
// on the request path. The format of the path should be
// "/cross-site/hostname/rest/of/path" to redirect the request to
// "<scheme>://hostname:<port>/rest/of/path", where <scheme> and <port>
// are the values for the instance of EmbeddedTestServer.
//
// By default, redirection will be done using HTTP 302 response, but in some
// cases (e.g. to preserve HTTP method and POST body across redirects as
// prescribed by https://tools.ietf.org/html/rfc7231#section-6.4.7) a test might
// want to use HTTP 307 response instead.  This can be accomplished by replacing
// "/cross-site/" URL substring above with "/cross-site-307/".
//
// |embedded_test_server| should not be running when passing it to this function
// because adding the request handler won't be thread safe.
void SetupCrossSiteRedirector(net::EmbeddedTestServer* embedded_test_server);

// Sets the access permission context in FileSystemAccessManagerImpl.
void SetFileSystemAccessPermissionContext(
    BrowserContext* browser_context,
    FileSystemAccessPermissionContext* permission_context);

// Waits until all resources have loaded in the given RenderFrameHost.
[[nodiscard]] bool WaitForRenderFrameReady(RenderFrameHost* rfh);

// Wait until the focused accessible node changes in any WebContents.
void WaitForAccessibilityFocusChange();

// Retrieve information about the node that's focused in the accessibility tree.
ui::AXNodeData GetFocusedAccessibilityNodeInfo(WebContents* web_contents);

// This is intended to be a robust way to assert that the accessibility
// tree eventually gets into the correct state, without worrying about
// the exact ordering of events received while getting there. Blocks
// until any change happens to the accessibility tree.
void WaitForAccessibilityTreeToChange(WebContents* web_contents);

// Searches the accessibility tree to see if any node's accessible name
// is equal to the given name. If not, repeatedly calls
// WaitForAccessibilityTreeToChange, above, and then checks again.
// Keeps looping until the text is found (or the test times out).
void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
                                                   std::string_view name);

// Get a snapshot of a web page's accessibility tree.
ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents);

// Get a snapshot of an accessibility tree given a `tree_id`.
ui::AXTreeUpdate GetAccessibilityTreeSnapshotFromId(
    const ui::AXTreeID& tree_id);

// Returns the root accessibility node for the given WebContents.
ui::AXPlatformNodeDelegate* GetRootAccessibilityNode(WebContents* web_contents);

// Finds an accessibility node matching the given criteria.
struct FindAccessibilityNodeCriteria {};
ui::AXPlatformNodeDelegate* FindAccessibilityNode(
    WebContents* web_contents,
    const FindAccessibilityNodeCriteria& criteria);
ui::AXPlatformNodeDelegate* FindAccessibilityNodeInSubtree(
    ui::AXPlatformNodeDelegate* node,
    const FindAccessibilityNodeCriteria& criteria);

#if BUILDFLAG(IS_WIN)
// Retrieve the specified interface from an accessibility node.
template <typename T>
Microsoft::WRL::ComPtr<T> QueryInterfaceFromNode(
    ui::AXPlatformNodeDelegate* node);

// Call GetPropertyValue with the given UIA property id with variant type
// VT_ARRAY | VT_UNKNOWN  on the target browser accessibility node to retrieve
// an array of automation elements, then validate the name property of the
// automation elements with the expected names.
void UiaGetPropertyValueVtArrayVtUnknownValidate(
    PROPERTYID property_id,
    ui::AXPlatformNodeDelegate* target_node,
    const std::vector<std::string>& expected_names);
#endif

// Returns the RenderWidgetHost that holds the keyboard lock.
RenderWidgetHost* GetKeyboardLockWidget(WebContents* web_contents);

// Returns the RenderWidgetHost that holds the mouse lock.
RenderWidgetHost* GetMouseLockWidget(WebContents* web_contents);

// Allows tests to drive keyboard lock functionality without requiring access
// to the RenderWidgetHostImpl header or setting up an HTTP test server.
// |codes| represents the set of keys to lock.  If |codes| has no value, then
// all keys will be considered locked.  If |codes| has a value, then at least
// one key must be specified.
void RequestKeyboardLock(
    WebContents* web_contents,
    std::optional<base::flat_set<ui::DomCode>> codes,
    base::OnceCallback<void(blink::mojom::KeyboardLockRequestResult)> callback);
void CancelKeyboardLock(WebContents* web_contents);

// Returns the screen orientation provider that's been set via
// WebContents::SetScreenOrientationDelegate(). May return null.
ScreenOrientationDelegate* GetScreenOrientationDelegate();

// Returns all the RenderWidgetHostViews inside the |web_contents| that are
// registered in the RenderWidgetHostInputEventRouter.
std::vector<RenderWidgetHostView*> GetInputEventRouterRenderWidgetHostViews(
    WebContents* web_contents);

// Returns the focused RenderWidgetHost.
RenderWidgetHost* GetFocusedRenderWidgetHost(WebContents* web_contents);

// Returns whether or not the RenderWidgetHost thinks it is focused.
bool IsRenderWidgetHostFocused(const RenderWidgetHost*);

// Returns the focused WebContents.
WebContents* GetFocusedWebContents(WebContents* web_contents);

// Watches title changes on a WebContents, blocking until an expected title is
// set.
class TitleWatcher : public WebContentsObserver {};

// Watches a RenderProcessHost and waits for a specified lifecycle event.
class RenderProcessHostWatcher : public RenderProcessHostObserver {};

// Implementation helper for:
// *) content-internal content::RenderProcessHostBadIpcMessageWaiter
//    (declared in //content/test/content_browser_test_utils_internal.h)
// *) content-public content::RenderProcessHostBadMojoMessageWaiter
//    (declared below)
// *) maybe in the future: similar helpers for chrome-layer BadMessageReason
class RenderProcessHostKillWaiter {};

// Helps tests to wait until the given renderer process is terminated because of
// a bad/invalid mojo message.
//
// Example usage:
//   RenderProcessHostBadMojoMessageWaiter kill_waiter(render_process_host);
//   ... test code that triggers a renderer kill ...
//   EXPECT_EQ("expected error message", kill_waiter.Wait());
class RenderProcessHostBadMojoMessageWaiter {};

// Watches for responses from the DOMAutomationController and keeps them in a
// queue. Useful for waiting for a message to be received.
class DOMMessageQueue {};

// Used to wait for a new WebContents to be created. Instantiate this object
// before the operation that will create the window.
class WebContentsAddedObserver {};

// Request a new frame be drawn, returns false if request fails.
bool RequestFrame(WebContents* web_contents);

// This class is intended to synchronize upon the submission of compositor
// frames from the renderer to the display compositor.
//
// This class enables observation of the provided
// RenderFrameMetadataProvider. Which notifies this of every
// subsequent frame submission. Observation ends upon the destruction of this
// class.
//
// Calling Wait will block the browser ui thread until the next time the
// renderer submits a frame.
//
// Tests interested in the associated RenderFrameMetadata will find it cached
// in the RenderFrameMetadataProvider.
class RenderFrameSubmissionObserver
    : public RenderFrameMetadataProvider::Observer {};

// This class is intended to synchronize the renderer main thread, renderer impl
// thread and the browser main thread.
//
// This is accomplished by sending an IPC to RenderWidget, then blocking until
// the ACK is received and processed.
//
// The ACK is sent from compositor thread, when the CompositorFrame is submited
// to the display compositor
// TODO(danakj): This class seems to provide the same as
// RenderFrameSubmissionObserver, consider using that instead.
class MainThreadFrameObserver {};

// Watches for an input msg to be consumed.
class InputMsgWatcher : public RenderWidgetHost::InputEventObserver {};

// Used to wait for a desired input event ack.
class InputEventAckWaiter : public RenderWidgetHost::InputEventObserver {};

// Sets up a ui::TestClipboard for use in browser tests. On Windows,
// clipboard is handled on the IO thread, BrowserTestClipboardScope
// hops messages onto the right thread.
class BrowserTestClipboardScope {};

// This observer is used to wait for its owner Frame to become focused.
class FrameFocusedObserver {};

// This observer is used to wait for its owner FrameTreeNode to become deleted.
class FrameDeletedObserver {};

// This class can be used to pause and resume navigations, based on a URL
// match. Note that it only keeps track of one navigation at a time.
// Navigations are paused automatically before hitting the network, and are
// resumed automatically if a Wait method is called for a future event.
//
// Note: This class is one time use only! After it successfully tracks a
// navigation it will ignore all subsequent navigations. Explicitly create
// multiple instances of this class if you want to pause multiple navigations.
//
// Note2: This class cannot be used with page activating navigations (e.g.
// BFCache, prerendering, etc.) as the activation doesn't run
// NavigationThrottles. Use TestActivationManager in these cases instead.
class TestNavigationManager : public WebContentsObserver {};

// Like TestNavigationManager but for page activating navigations like
// Back-Forward Cache restores and prerendering activations. This can be used
// to pause and resume the navigation at certain points during an activation.
// Note that only a single navigation will be tracked by this manager. When
// this object is live, a matching navigation will be automatically paused at
// kBeforeChecks and resumed automatically when a Wait method is called.
class TestActivationManager : public WebContentsObserver {};

class NavigationHandleCommitObserver : public content::WebContentsObserver {};

// A test utility that monitors console messages sent to a WebContents. This
// can be used to wait for a message that matches a specific filter, an
// arbitrary message, or monitor all messages sent to the WebContents' console.
class WebContentsConsoleObserver : public WebContentsObserver {};

// A helper class to get DevTools inspector log messages (e.g. network errors).
class DevToolsInspectorLogWatcher : public DevToolsAgentHostClient {};

// Static methods that simulates Mojo methods as if they were called by a
// renderer. Used to simulate a compromised renderer.
class PwnMessageHelper {};

#if defined(USE_AURA)

// Tests that a |render_widget_host_view| stores a stale content when its frame
// gets evicted. |render_widget_host_view| has to be a RenderWidgetHostViewAura.
void VerifyStaleContentOnFrameEviction(
    RenderWidgetHostView* render_widget_host_view);

#endif  // defined(USE_AURA)

// Helper class to interpose on Blob URL registrations, replacing the URL
// contained in incoming registration requests with the specified URL.
class BlobURLStoreInterceptor
    : public blink::mojom::BlobURLStoreInterceptorForTesting {};

// Load the given |url| with |network_context| and return the |net::Error| code.
//
// This overload simulates loading through a URLLoaderFactory created for a
// Browser process.
int LoadBasicRequest(network::mojom::NetworkContext* network_context,
                     const GURL& url,
                     int load_flags = net::LOAD_NORMAL);

// Load the given |url| via URLLoaderFactory created by |frame|.  Return the
// |net::Error| code.
//
// This overload simulates loading through a URLLoaderFactory created for a
// Renderer process (the factory is driven from the Test/Browser process, but
// has the same properties as factories vended to the Renderer process that
// hosts the |frame|).
int LoadBasicRequest(RenderFrameHost* frame, const GURL& url);

// Ensures that all StoragePartitions for the given BrowserContext have their
// cookies flushed to disk.
void EnsureCookiesFlushed(BrowserContext* browser_context);

// Performs a simple auto-resize flow and ensures that the embedder gets a
// single response messages back from the guest, with the expected values.
bool TestGuestAutoresize(WebContents* embedder_web_contents,
                         RenderFrameHost* guest_main_frame);

// This class allows monitoring of mouse events received by a specific
// RenderWidgetHost.
class RenderWidgetHostMouseEventMonitor {};

// Helper class to track and allow waiting for navigation start events.
class DidStartNavigationObserver : public WebContentsObserver {};

// Tracks the creation of RenderFrameProxyHosts that have
// CrossProcessFrameConnectors, and records the initial (post-construction)
// device scale factor in the CrossProcessFrameConnector.
class ProxyDSFObserver {};

// Helper used by the wrapper class below. Compares the output of the given
// |web_contents| to the PNG file at |expected_path| across the region defined
// by |snapshot_size| and returns true if the images are equivalent. Uses a
// ManhattanDistancePixelComparator which allows some small differences.  If
// the flag switches::kRebaselinePixelTests (--rebaseline-pixel-tests) is set,
// this function will (over)write the reference file with the produced output.
bool CompareWebContentsOutputToReference(
    WebContents* web_contents,
    const base::FilePath& expected_path,
    const gfx::Size& snapshot_size,
    const cc::PixelComparator& comparator =
        cc::ManhattanDistancePixelComparator());

RenderFrameHostChangedCallback;

// Runs callback at RenderFrameHostChanged time. On cross-RFH navigations, this
// will run the callback after the new RenderFrameHost committed and is set as
// the current RenderFrameHost, etc. but before the old RenderFrameHost gets
// unloaded.
class RenderFrameHostChangedCallbackRunner : public WebContentsObserver {};

// Calls |callback| whenever a navigation finishes in |render_frame_host|.
class DidFinishNavigationObserver : public WebContentsObserver {};

// Wait for a new WebContents to be created, and for it to finish navigation.
// It will detect WebContents creation after construction, even if it's before
// Wait() is called.  The intended pattern is:
//
// CreateAndLoadWebContentsObserver observer;
// ...Do something that creates one WebContents and causes it to navigate...
// observer.Wait();
class CreateAndLoadWebContentsObserver {};

// Waits for the given number of calls to
// WebContentsObserver::OnCookiesAccessed.
class CookieChangeObserver : public content::WebContentsObserver {};

// Wait for the creation of Speculative RFH without throttling the navigation.
// Since the TestNavigationManager will throttle the navigation, using with
// class with TestNavigationManager is not recommended. Manually driving the
// run loop will be required to receive the events in both objects. We recommend
// to use TestNavigationManager for simply driving the navigation. However if it
// is required to intercept the navigation with other observers such as
// CommitPauser, it would be better to use SpeculativeRenderFrameHostObserver to
// ensure the speculative RFH to avoid interference caused by the
// TestNavigationManager.
class SpeculativeRenderFrameHostObserver : public content::WebContentsObserver {};

class SpareRenderProcessObserver {};

[[nodiscard]] base::CallbackListSubscription
RegisterWebContentsCreationCallback(
    base::RepeatingCallback<void(WebContents*)> callback);

// Functions to traverse history and wait until the traversal completes, even if
// the loading is stopped halfway (e.g. if a BackForwardCache entry is evicted
// during the restoration, causing the old NavigationRequest to be reset and a
// new NavigationRequest to be restarted). These are wrappers around the
// same-named methods of the `NavigationController`.
[[nodiscard]] bool HistoryGoToIndex(WebContents* wc, int index);
[[nodiscard]] bool HistoryGoToOffset(WebContents* wc, int offset);
[[nodiscard]] bool HistoryGoBack(WebContents* wc);
[[nodiscard]] bool HistoryGoForward(WebContents* wc);

#if BUILDFLAG(IS_MAC)
// Grant native windows the ability to activate, allowing them to become key
// and/or main. This can be useful to enable when the process hosting the window
// is a standalone executable without an Info.plist.
bool EnableNativeWindowActivation();
#endif  // BUILDFLAG(IS_MAC)

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Set the global factory for CapturedSurfaceController objects.
void SetCapturedSurfaceControllerFactoryForTesting(
    base::RepeatingCallback<std::unique_ptr<MockCapturedSurfaceController>(
        GlobalRenderFrameHostId,
        WebContentsMediaCaptureId)> factory);
#endif  // !BUILDFLAG(IS_ANDROID)

}  // namespace content

#endif  // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_