chromium/content/test/content_browser_test_utils_internal.h

// Copyright 2014 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_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
#define CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_

// A collection of functions designed for use with content_shell based browser
// tests internal to the content/ module.
// Note: If a function here also works with browser_tests, it should be in
// the content public API.

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

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/renderer_host/back_forward_cache_metrics.h"
#include "content/browser/renderer_host/navigation_type.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom-forward.h"
#include "third_party/blink/public/mojom/choosers/popup_menu.mojom.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
#include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h"
#include "url/gurl.h"

namespace content {

class FrameTreeNode;
class RenderFrameHost;
class RenderFrameHostImpl;
class RenderWidgetHostImpl;
class Shell;
class SiteInstance;
class SiteInstanceGroup;
class ToRenderFrameHost;

// Navigates the frame represented by |node| to |url|, blocking until the
// navigation finishes. Returns true if the navigation succeedd and the final
// URL matches |url|.
bool NavigateFrameToURL(FrameTreeNode* node, const GURL& url);

// Sets the DialogManager to proceed by default or not when showing a
// BeforeUnload dialog, and if it proceeds, what value to return.
void SetShouldProceedOnBeforeUnload(Shell* shell, bool proceed, bool success);

// Extends the ToRenderFrameHost mechanism to FrameTreeNodes.
RenderFrameHost* ConvertToRenderFrameHost(FrameTreeNode* frame_tree_node);

// Helper function to navigate a window to a |url|, using a browser-initiated
// navigation that will stay in the same BrowsingInstance.  Most
// browser-initiated navigations swap BrowsingInstances, but some tests need a
// navigation to swap processes for cross-site URLs (even outside of
// --site-per-process) while staying in the same BrowsingInstance.
[[nodiscard]] bool NavigateToURLInSameBrowsingInstance(Shell* window,
                                                       const GURL& url);

// Helper function to checks for a subframe navigation starting  in
// `start_site_instance` and results in an error page correctly transitions to
// `end_site_instance` based on whether error page isolation is enabled or not.
[[nodiscard]] bool IsExpectedSubframeErrorTransition(
    SiteInstance* start_site_instance,
    SiteInstance* end_site_instance);

// Creates an iframe with id |frame_id| and src set to |url|, and appends it to
// the main frame's document, waiting until the RenderFrameHostCreated
// notification is received by the browser. If |wait_for_navigation| is true,
// will also wait for the first navigation in the iframe to finish. Returns the
// RenderFrameHost of the iframe. |extra_params| is a struct that allows
// for optional parameters to be specified for the subframe.
struct ExtraParams {};
RenderFrameHost* CreateSubframe(WebContentsImpl* web_contents,
                                std::string frame_id,
                                const GURL& url,
                                bool wait_for_navigation);
RenderFrameHost* CreateSubframe(RenderFrameHost* parent,
                                std::string frame_id,
                                const GURL& url,
                                bool wait_for_navigation);
RenderFrameHost* CreateSubframe(RenderFrameHost* parent,
                                std::string frame_id,
                                const GURL& url,
                                bool wait_for_navigation,
                                ExtraParams extra_params);

// Returns the frames visited by |RenderFrameHostImpl::ForEachRenderFrameHost|
// in the same order.
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
    RenderFrameHostImpl* starting_rfh);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(
    RenderFrameHostImpl* starting_rfh);
// Returns the frames visited by |WebContentsImpl::ForEachRenderFrameHost|
// in the same order.
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
    WebContentsImpl* web_contents);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(WebContentsImpl* web_contents);

// Open a new popup passing no URL to window.open, which results in a blank page
// and only the initial entry. Returns the newly created shell. Also saves the
// reference to the opened window in the "last_opened_window" variable in JS.
Shell* OpenBlankWindow(WebContentsImpl* web_contents);

// Pop open a new window that navigates to |url|. Returns the newly created
// shell. Also saves the reference to the opened window in the
// "last_opened_window" variable in JS.
Shell* OpenWindow(WebContentsImpl* web_contents, const GURL& url);

// Creates compact textual representations of the state of the frame tree that
// is appropriate for use in assertions.
//
// The diagrams show frame tree structure, the SiteInstance of current frames,
// presence of pending frames, and the SiteInstanceGroups of any and all
// proxies. They look like this:
//
//        Site A (D pending) -- proxies for B {C,E}
//          |--Site B --------- proxies for A {C,E}
//          +--Site C --------- proxies for B A
//               |--Site A ---- proxies for B {C,E}
//               +--Site A ---- proxies for B {C,E}
//                    +--Site E -- proxies for A B
//       Where A = http://127.0.0.1/
//             B = http://foo.com/ (no process)
//             C = http://bar.com/
//             D = http://next.com/
//             E = data:nonce_E
//
// SiteInstances are assigned single-letter names (A, B, C) which are remembered
// across invocations of the pretty-printer. Port numbers are excluded from the
// descriptions by default for DepictFrameTree. Isolated sandboxed SiteInstances
// are denoted with "(sandboxed)".
//
// SiteInstanceGroups with more than once SiteInstance are denoted as a set of
// the SiteInstances in the group. See comment for `GetGroupName`. In this case,
// E is in C's SiteInstanceGroup, denoted {C,E}. Note that SiteInstanceGroups
// may show SiteInstances that are no longer in the FrameTree. For example, if a
// subframe B does a same-SiteInstanceGroup navigation to data:nonce_C, B's
// SiteInstance is kept alive by a FrameNavigationEntry, and it retains its
// group and process because the active frame count is tracked on the
// SiteInstanceGroup (shared with data:nonce_C) and not the B SiteInstance
// itself. (This is not necessary but has no impact outside of DepictFrameTree
// output). That means it still exists from the perspective
// of DepictFrameTree.
class FrameTreeVisualizer {};

// Uses FrameTreeVisualizer to draw a text representation of the FrameTree that
// is appropriate for use in assertions. If you are going to depict multiple
// trees in a single test, you might want to construct a longer-lived instance
// of FrameTreeVisualizer as this will ensure consistent naming of the site
// instances across all calls.
std::string DepictFrameTree(FrameTreeNode& root);

// Uses window.open to open a popup from the frame |opener| with the specified
// |url|, |name| and window |features|. |expect_return_from_window_open| is used
// to indicate if the caller expects window.open() to return a non-null value.
// Waits for the navigation to |url| to finish and then returns the new popup's
// Shell.  Note that since this navigation to |url| is renderer-initiated, it
// won't cause a process swap unless used in --site-per-process mode.
Shell* OpenPopup(const ToRenderFrameHost& opener,
                 const GURL& url,
                 const std::string& name,
                 const std::string& features,
                 bool expect_return_from_window_open);

// Same as above, but with an empty |features| and
// |expect_return_from_window_open| assumed to be true..
Shell* OpenPopup(const ToRenderFrameHost& opener,
                 const GURL& url,
                 const std::string& name);

// Helper for mocking choosing a file via a file dialog.
class FileChooserDelegate : public WebContentsDelegate {};

// This class is a TestNavigationManager that only monitors notifications within
// the given frame tree node.
class FrameTestNavigationManager : public TestNavigationManager {};

// An observer that can wait for a specific URL to be committed in a specific
// frame.
// Note: it does not track the start of a navigation, unlike other observers.
class UrlCommitObserver : WebContentsObserver {};

// Waits for a kill of the given RenderProcessHost and returns the
// BadMessageReason that caused a //content-triggerred kill.
//
// Example usage:
//   RenderProcessHostBadIpcMessageWaiter kill_waiter(render_process_host);
//   ... test code that triggers a renderer kill ...
//   EXPECT_EQ(bad_message::RFH_INVALID_ORIGIN_ON_COMMIT, kill_waiter.Wait());
//
// Tests that don't expect kills (e.g. tests where a renderer process exits
// normally, like RenderFrameHostManagerTest.ProcessExitWithSwappedOutViews)
// should use RenderProcessHostWatcher instead of
// RenderProcessHostBadIpcMessageWaiter.
class RenderProcessHostBadIpcMessageWaiter {};

// One-shot helper that listens for creation of a new popup widget.
class CreateNewPopupWidgetInterceptor
    : public blink::mojom::LocalFrameHostInterceptorForTesting {};

class ShowPopupWidgetWaiter
    : public blink::mojom::PopupWidgetHostInterceptorForTesting {};

// This observer waits until WebContentsObserver::OnRendererUnresponsive
// notification.
class UnresponsiveRendererObserver : public WebContentsObserver {};

// Helper class that overrides the JavaScriptDialogManager of a WebContents
// to endlessly block on beforeunload.
class BeforeUnloadBlockingDelegate : public JavaScriptDialogManager,
                                     public WebContentsDelegate {};

// Captures various properties of the NavigationHandle on DidFinishNavigation.
// By default, captures the next navigation (either for a specific frame or
// any frame in the WebContents) and waits until the navigation completely
// loads. Can be configured to not wait for load to finish, and also to capture
// properties for multiple navigations, as we save the values in arrays.
class FrameNavigateParamsCapturer : public WebContentsObserver {};

// This observer keeps track of the number of created RenderFrameHosts.  Tests
// can use this to ensure that a certain number of child frames has been
// created after navigating (defaults to 1), and can also supply a callback to
// run on every RenderFrameCreated call.
class RenderFrameHostCreatedObserver : public WebContentsObserver {};

// The standard DisabledReason used in testing. The functions below use this
// reason and tests will need to assert that it appears.
BackForwardCache::DisabledReason RenderFrameHostDisabledForTestingReason();
// Disable using the standard testing DisabledReason.
void DisableBFCacheForRFHForTesting(RenderFrameHost* render_frame_host);
void DisableBFCacheForRFHForTesting(GlobalRenderFrameHostId id);

// Changes the WebContents and active entry user agent override from
// DidStartNavigation().
class UserAgentInjector : public WebContentsObserver {};

// Just like RenderFrameHostWrapper but holds and gives access to a
// RenderFrameHostImpl.
class RenderFrameHostImplWrapper : public RenderFrameHostWrapper {};

// Use this class to wait for all RenderFrameHosts in a WebContents that are
// inactive (pending deletion, stored in BackForwardCache, prerendered, etc) to
// be deleted. This will triggerBackForwardCache flushing and prerender
// cancellations..
class InactiveRenderFrameHostDeletionObserver : public WebContentsObserver {};

class TestNavigationObserverInternal : public TestNavigationObserver {};

// Return the descendant of `rfh` found by selecting children according to
// `descendant_indices`. E.g. `DescendantRenderFrameHostImplAt(rfh, {0, 1}) will
// return the child at index 1 of the child at index 0 of `rfh`.
RenderFrameHostImpl* DescendantRenderFrameHostImplAt(
    const ToRenderFrameHost& adapter,
    std::vector<size_t> descendant_indices);

class EffectiveURLContentBrowserTestContentBrowserClient
    : public ContentBrowserTestContentBrowserClient {};

// Class that requests that all pages belonging to the provided site get loaded
// in a non-default StoragePartition.
class CustomStoragePartitionBrowserClient
    : public ContentBrowserTestContentBrowserClient {};

// Helper that waits for a request from the specified `RenderFrameHost` to send
// `CommitNavigation()` to the browser.
class CommitNavigationPauser
    : public RenderFrameHostImpl::CommitCallbackInterceptor {};

// Blocks the current execution until the renderer main thread in the main frame
// is in a steady state, so the caller can issue an `viz::CopyOutputRequest`
// against the current `WebContents`.
void WaitForCopyableViewInWebContents(WebContents* web_contents);

// Blocks the current execution until the renderer main thread in the subframe
// is in a steady state, so the caller can issue an `viz::CopyOutputRequest`
// against its view.
void WaitForCopyableViewInFrame(RenderFrameHost* render_frame_host);

// Blocks the current execution until the frame submitted via the browser's
// compositor is presented on the screen.
void WaitForBrowserCompositorFramePresented(WebContents* web_contents);

// Forces the browser to submit a compositor frame, even if nothing has changed
// in the viewport. Use `WaitForBrowserCompositorFramePresented()` to wait for
// the frame's presentation.
void ForceNewCompositorFrameFromBrowser(WebContents* web_contents);

// Sets up a /redirect-on-second-navigation?url endpoint on the provided
// `server`, which will return a 200 OK response for the first request, and
// redirect the second request to `url` provided in the query param. This should
// be called before starting `server`.
void AddRedirectOnSecondNavigationHandler(net::EmbeddedTestServer* server);

}  // namespace content

#endif  // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_