#ifndef CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
#define CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
#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/web_contents/web_contents_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 "ipc/constants.mojom.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 Shell;
class SiteInstance;
class SiteInstanceGroup;
class ToRenderFrameHost;
bool NavigateFrameToURL(FrameTreeNode* node, const GURL& url);
void SetShouldProceedOnBeforeUnload(Shell* shell, bool proceed, bool success);
RenderFrameHost* ConvertToRenderFrameHost(FrameTreeNode* frame_tree_node);
[[nodiscard]] bool NavigateToURLInSameBrowsingInstance(Shell* window,
const GURL& url);
[[nodiscard]] bool IsExpectedSubframeErrorTransition(
SiteInstance* start_site_instance,
SiteInstance* end_site_instance);
struct ExtraParams {
std::string sandbox_flags = "";
};
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);
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
RenderFrameHostImpl* starting_rfh);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(
RenderFrameHostImpl* starting_rfh);
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
WebContentsImpl* web_contents);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(WebContentsImpl* web_contents);
Shell* OpenBlankWindow(WebContentsImpl* web_contents);
Shell* OpenWindow(WebContentsImpl* web_contents, const GURL& url);
class FrameTreeVisualizer {
public:
FrameTreeVisualizer();
FrameTreeVisualizer(const FrameTreeVisualizer&) = delete;
FrameTreeVisualizer& operator=(const FrameTreeVisualizer&) = delete;
~FrameTreeVisualizer();
std::string DepictFrameTree(FrameTreeNode* root);
private:
std::string GetName(SiteInstance* site_instance);
std::string GetGroupName(SiteInstanceGroup* group);
GURL GetUrlWithoutPort(const GURL& url);
std::vector<SiteInstanceId> seen_site_instance_ids_;
};
std::string DepictFrameTree(FrameTreeNode& root);
Shell* OpenPopup(const ToRenderFrameHost& opener,
const GURL& url,
const std::string& name,
const std::string& features,
bool expect_return_from_window_open);
Shell* OpenPopup(const ToRenderFrameHost& opener,
const GURL& url,
const std::string& name);
class FileChooserDelegate : public WebContentsDelegate {
public:
FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback);
FileChooserDelegate(std::vector<base::FilePath> files,
const base::FilePath& base_dir,
base::OnceClosure callback);
~FileChooserDelegate() override;
void RunFileChooser(RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) override;
const blink::mojom::FileChooserParams& params() const { return *params_; }
private:
std::vector<base::FilePath> files_;
const base::FilePath base_dir_;
base::OnceClosure callback_;
blink::mojom::FileChooserParamsPtr params_;
};
class FrameTestNavigationManager : public TestNavigationManager {
public:
FrameTestNavigationManager(FrameTreeNodeId frame_tree_node_id,
WebContents* web_contents,
const GURL& url);
FrameTestNavigationManager(const FrameTestNavigationManager&) = delete;
FrameTestNavigationManager& operator=(const FrameTestNavigationManager&) =
delete;
private:
bool ShouldMonitorNavigation(NavigationHandle* handle) override;
FrameTreeNodeId filtering_frame_tree_node_id_;
};
class UrlCommitObserver : WebContentsObserver {
public:
explicit UrlCommitObserver(FrameTreeNode* frame_tree_node, const GURL& url);
UrlCommitObserver(const UrlCommitObserver&) = delete;
UrlCommitObserver& operator=(const UrlCommitObserver&) = delete;
~UrlCommitObserver() override;
void Wait();
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
FrameTreeNodeId frame_tree_node_id_;
GURL url_;
base::RunLoop run_loop_;
};
class RenderProcessHostBadIpcMessageWaiter {
public:
explicit RenderProcessHostBadIpcMessageWaiter(
RenderProcessHost* render_process_host);
RenderProcessHostBadIpcMessageWaiter(
const RenderProcessHostBadIpcMessageWaiter&) = delete;
RenderProcessHostBadIpcMessageWaiter& operator=(
const RenderProcessHostBadIpcMessageWaiter&) = delete;
[[nodiscard]] std::optional<bad_message::BadMessageReason> Wait();
private:
RenderProcessHostKillWaiter internal_waiter_;
};
class UnresponsiveRendererObserver : public WebContentsObserver {
public:
explicit UnresponsiveRendererObserver(WebContents* web_contents);
UnresponsiveRendererObserver(const UnresponsiveRendererObserver&) = delete;
UnresponsiveRendererObserver& operator=(const UnresponsiveRendererObserver&) =
delete;
~UnresponsiveRendererObserver() override;
RenderProcessHost* Wait(base::TimeDelta timeout = base::TimeDelta::Max());
private:
void OnRendererUnresponsive(RenderProcessHost* render_process_host) override;
raw_ptr<RenderProcessHost> captured_render_process_host_ = nullptr;
base::RunLoop run_loop_;
};
class BeforeUnloadBlockingDelegate : public JavaScriptDialogManager,
public WebContentsDelegate {
public:
explicit BeforeUnloadBlockingDelegate(WebContentsImpl* web_contents);
BeforeUnloadBlockingDelegate(const BeforeUnloadBlockingDelegate&) = delete;
BeforeUnloadBlockingDelegate& operator=(const BeforeUnloadBlockingDelegate&) =
delete;
~BeforeUnloadBlockingDelegate() override;
void Wait();
JavaScriptDialogManager* GetJavaScriptDialogManager(
WebContents* source) override;
bool IsBackForwardCacheSupported(WebContents& web_contents) override;
void RunJavaScriptDialog(WebContents* web_contents,
RenderFrameHost* render_frame_host,
JavaScriptDialogType dialog_type,
const std::u16string& message_text,
const std::u16string& default_prompt_text,
DialogClosedCallback callback,
bool* did_suppress_message) override;
void RunBeforeUnloadDialog(WebContents* web_contents,
RenderFrameHost* render_frame_host,
bool is_reload,
DialogClosedCallback callback) override;
bool HandleJavaScriptDialog(WebContents* web_contents,
bool accept,
const std::u16string* prompt_override) override;
void CancelDialogs(WebContents* web_contents, bool reset_state) override {}
private:
raw_ptr<WebContentsImpl> web_contents_;
DialogClosedCallback callback_;
std::unique_ptr<base::RunLoop> run_loop_ = std::make_unique<base::RunLoop>();
};
class FrameNavigateParamsCapturer : public WebContentsObserver {
public:
explicit FrameNavigateParamsCapturer(WebContents* contents);
explicit FrameNavigateParamsCapturer(FrameTreeNode* node);
~FrameNavigateParamsCapturer() override;
void Wait();
void set_navigations_remaining(int count) {
DCHECK_GE(count, 0);
navigations_remaining_ = count;
}
void set_wait_for_load(bool wait_for_load) { wait_for_load_ = wait_for_load; }
ui::PageTransition transition() const {
EXPECT_EQ(1U, transitions_.size());
return transitions_[0];
}
NavigationType navigation_type() const {
EXPECT_EQ(1U, navigation_types_.size());
return navigation_types_[0];
}
bool is_same_document() const {
EXPECT_EQ(1U, is_same_documents_.size());
return is_same_documents_[0];
}
bool is_renderer_initiated() const {
EXPECT_EQ(1U, is_renderer_initiateds_.size());
return is_renderer_initiateds_[0];
}
bool did_replace_entry() const {
EXPECT_EQ(1U, did_replace_entries_.size());
return did_replace_entries_[0];
}
bool has_user_gesture() const {
EXPECT_EQ(1U, has_user_gestures_.size());
return has_user_gestures_[0];
}
bool is_overriding_user_agent() const {
EXPECT_EQ(1U, is_overriding_user_agents_.size());
return is_overriding_user_agents_[0];
}
bool is_error_page() const {
EXPECT_EQ(1U, is_error_pages_.size());
return is_error_pages_[0];
}
const std::vector<ui::PageTransition>& transitions() { return transitions_; }
const std::vector<GURL>& urls() { return urls_; }
const std::vector<NavigationType>& navigation_types() {
return navigation_types_;
}
const std::vector<bool>& is_same_documents() { return is_same_documents_; }
const std::vector<bool>& did_replace_entries() {
return did_replace_entries_;
}
const std::vector<bool>& has_user_gestures() { return has_user_gestures_; }
const std::vector<bool>& is_overriding_user_agents() {
return is_overriding_user_agents_;
}
const std::vector<bool>& is_error_pages() { return is_error_pages_; }
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void DidStopLoading() override;
std::optional<FrameTreeNodeId> frame_tree_node_id_;
int navigations_remaining_ = 1;
bool wait_for_load_ = true;
std::vector<ui::PageTransition> transitions_;
std::vector<GURL> urls_;
std::vector<NavigationType> navigation_types_;
std::vector<bool> is_same_documents_;
std::vector<bool> did_replace_entries_;
std::vector<bool> is_renderer_initiateds_;
std::vector<bool> has_user_gestures_;
std::vector<bool> is_overriding_user_agents_;
std::vector<bool> is_error_pages_;
base::RunLoop loop_;
};
class RenderFrameHostCreatedObserver : public WebContentsObserver {
public:
using OnRenderFrameHostCreatedCallback =
base::RepeatingCallback<void(RenderFrameHost*)>;
explicit RenderFrameHostCreatedObserver(WebContents* web_contents);
RenderFrameHostCreatedObserver(WebContents* web_contents,
int expected_frame_count);
RenderFrameHostCreatedObserver(
WebContents* web_contents,
OnRenderFrameHostCreatedCallback on_rfh_created);
~RenderFrameHostCreatedObserver() override;
RenderFrameHost* Wait();
RenderFrameHost* last_rfh() { return last_rfh_; }
private:
void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
int expected_frame_count_ = 1;
int frames_created_ = 0;
base::RunLoop run_loop_;
raw_ptr<RenderFrameHost, AcrossTasksDanglingUntriaged> last_rfh_ = nullptr;
OnRenderFrameHostCreatedCallback on_rfh_created_;
};
BackForwardCache::DisabledReason RenderFrameHostDisabledForTestingReason();
void DisableBFCacheForRFHForTesting(RenderFrameHost* render_frame_host);
void DisableBFCacheForRFHForTesting(GlobalRenderFrameHostId id);
class UserAgentInjector : public WebContentsObserver {
public:
UserAgentInjector(WebContents* web_contents, const std::string& user_agent)
: UserAgentInjector(web_contents,
blink::UserAgentOverride::UserAgentOnly(user_agent),
true) {}
UserAgentInjector(WebContents* web_contents,
const blink::UserAgentOverride& ua_override,
bool is_overriding_user_agent = true)
: WebContentsObserver(web_contents),
user_agent_override_(ua_override),
is_overriding_user_agent_(is_overriding_user_agent) {}
void DidStartNavigation(NavigationHandle* navigation_handle) override;
void set_is_overriding_user_agent(bool is_overriding_user_agent) {
is_overriding_user_agent_ = is_overriding_user_agent;
}
void set_user_agent_override(const std::string& user_agent) {
user_agent_override_ = blink::UserAgentOverride::UserAgentOnly(user_agent);
}
private:
blink::UserAgentOverride user_agent_override_;
bool is_overriding_user_agent_ = true;
};
class RenderFrameHostImplWrapper : public RenderFrameHostWrapper {
public:
explicit RenderFrameHostImplWrapper(RenderFrameHost* rfh);
RenderFrameHostImpl* get() const;
RenderFrameHostImpl& operator*() const;
RenderFrameHostImpl* operator->() const;
};
class InactiveRenderFrameHostDeletionObserver : public WebContentsObserver {
public:
explicit InactiveRenderFrameHostDeletionObserver(WebContents* content);
~InactiveRenderFrameHostDeletionObserver() override;
void Wait();
private:
void RenderFrameDeleted(RenderFrameHost*) override;
void CheckCondition();
std::unique_ptr<base::RunLoop> loop_;
std::set<raw_ptr<RenderFrameHost, SetExperimental>> inactive_rfhs_;
};
class TestNavigationObserverInternal : public TestNavigationObserver {
public:
using TestNavigationObserver::TestNavigationObserver;
~TestNavigationObserverInternal() override = default;
void OnDidFinishNavigation(NavigationHandle* navigation_handle) override;
NavigationType last_navigation_type() const { return last_navigation_type_; }
private:
NavigationType last_navigation_type_ = NAVIGATION_TYPE_UNKNOWN;
};
RenderFrameHostImpl* DescendantRenderFrameHostImplAt(
const ToRenderFrameHost& adapter,
std::vector<size_t> descendant_indices);
class EffectiveURLContentBrowserTestContentBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
explicit EffectiveURLContentBrowserTestContentBrowserClient(
bool requires_dedicated_process);
EffectiveURLContentBrowserTestContentBrowserClient(
const GURL& url_to_modify,
const GURL& url_to_return,
bool requires_dedicated_process);
~EffectiveURLContentBrowserTestContentBrowserClient() override;
void AddTranslation(const GURL& url_to_modify, const GURL& url_to_return);
private:
std::optional<GURL> GetEffectiveURL(BrowserContext* browser_context,
const GURL& url) override;
bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
const GURL& effective_site_url) override;
EffectiveURLContentBrowserClientHelper helper_;
};
class CustomStoragePartitionBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
explicit CustomStoragePartitionBrowserClient(const GURL& site_to_isolate);
StoragePartitionConfig GetStoragePartitionConfigForSite(
BrowserContext* browser_context,
const GURL& site) override;
private:
GURL site_to_isolate_;
};
class CommitNavigationPauser
: public RenderFrameHostImpl::CommitCallbackInterceptor {
public:
explicit CommitNavigationPauser(RenderFrameHostImpl* rfh);
~CommitNavigationPauser() override;
void WaitForCommitAndPause();
void ResumePausedCommit();
void DiscardPausedCommit();
private:
bool WillProcessDidCommitNavigation(
NavigationRequest* request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override;
base::RunLoop loop_;
base::WeakPtr<NavigationRequest> paused_request_;
mojom::DidCommitProvisionalLoadParamsPtr paused_params_;
mojom::DidCommitProvisionalLoadInterfaceParamsPtr paused_interface_params_;
};
void AddRedirectOnSecondNavigationHandler(net::EmbeddedTestServer* server);
class LoadingStartObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void()>;
LoadingStartObserver(WebContents* web_contents, Callback callback);
~LoadingStartObserver() override;
private:
void DidStartLoading() override;
Callback callback_;
};
class LoadingStopObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void()>;
LoadingStopObserver(WebContents* web_contents, Callback callback);
~LoadingStopObserver() override;
private:
void DidStopLoading() override;
Callback callback_;
};
class LoadFinishObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void(RenderFrameHost*, const GURL&)>;
LoadFinishObserver(WebContents* web_contents, Callback callback);
~LoadFinishObserver() override;
private:
void DidFinishLoad(RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
Callback callback_;
};
}
#endif