// 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_