blob: 679e45e35f8af86c42a51019fab748a7d19e89a9 [file] [log] [blame]
// Copyright 2021 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_FENCED_FRAME_TEST_UTIL_H_
#define CONTENT_PUBLIC_TEST_FENCED_FRAME_TEST_UTIL_H_
#include <vector>
#include "base/compiler_specific.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/types/optional_ref.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/base/net_errors.h"
#include "third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_pointer_properties.h"
#include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom.h"
class GURL;
namespace gfx {
class PointF;
}
namespace content {
class RenderFrameHost;
class FencedFrameURLMapping;
class FencedFrameReporter;
class ToRenderFrameHost;
namespace test {
// Browser tests can use this class to more conveniently leverage fenced frames.
class FencedFrameTestHelper {
public:
explicit FencedFrameTestHelper();
~FencedFrameTestHelper();
FencedFrameTestHelper(const FencedFrameTestHelper&) = delete;
FencedFrameTestHelper& operator=(const FencedFrameTestHelper&) = delete;
// This method creates a new fenced frame in `mode` rooted at
// `fenced_frame_parent` that is navigated to `url`. This method waits for the
// navigation to `url` to commit, and returns the `RenderFrameHost` that
// committed the navigation if it succeeded. Otherwise, it returns `nullptr`.
// See `NavigationFrameInFencedFrameTree()` documentation for the
// `expected_error_code` parameter.
RenderFrameHost* CreateFencedFrame(
RenderFrameHost* fenced_frame_parent,
const GURL& url,
net::Error expected_error_code = net::OK,
blink::FencedFrame::DeprecatedFencedFrameMode mode =
blink::FencedFrame::DeprecatedFencedFrameMode::kDefault,
bool wait_for_load = true);
// This method is similar to `FencedFrameTestHelper::CreateFencedFrame` but
// doesn't wait until the fenced frame completes loading.
void CreateFencedFrameAsync(RenderFrameHost* fenced_frame_parent_rfh,
const GURL& url);
void NavigateFencedFrameUsingFledge(RenderFrameHost* fenced_frame_parent,
const GURL& url,
const std::string fenced_frame_id);
// This method provides a way to navigate frames within a fenced frame's tree,
// and synchronously wait for the load to finish. This method returns the
// `RenderFrameHost` that the navigation committed to if it was successful
// (which may be different from the one that navigation started in), and
// `nullptr` otherwise. It takes an `expected_error_code` in case the
// navigation to `url` fails, which can be detected on a per-error-code basis.
// TODO(crbug.com/40820418): Directly use TestFrameNavigationObserver instead
// of relying on this method.
RenderFrameHost* NavigateFrameInFencedFrameTree(
RenderFrameHost* rfh,
const GURL& url,
net::Error expected_error_code = net::OK,
bool wait_for_load = true);
// Helper function for event reporting tests that sends out a request. This is
// used to see if this request or the actual event reached the server first.
// If this reaches the server first, we know that the event was not sent.
void SendBasicRequest(WebContents* web_contents,
GURL url,
std::optional<std::string> content = std::nullopt);
// Returns the last created fenced frame. This can be used by embedders who
// must create fenced frames from script but need to get the fence frame's
// inner root RenderFrameHost.
// This method will return nullptr if no fenced frames were created.
static RenderFrameHost* GetMostRecentlyAddedFencedFrame(RenderFrameHost* rfh);
// Returns a vector of all child fenced frames given a parent `rfh`. This can
// be used by embedders who must create multiple fenced frames from script but
// need to get their inner root RenderFrameHosts.
static std::vector<RenderFrameHost*> GetChildFencedFrameHosts(
RenderFrameHost* rfh);
// Class for observing visibility changes in fenced frame roots, such as when
// they enter or leave the viewport.
class FencedFrameVisibilityObserver : public WebContentsObserver {
public:
// If `fenced_frame_root` is nullptr, `Wait()` will terminate when a
// newly-created fenced frame root has `visibility`. Otherwise, `Wait()`
// will terminate when the node specified by `fenced_frame_root` has
// `visibility`.
explicit FencedFrameVisibilityObserver(
WebContents* web_contents,
blink::mojom::FrameVisibility visibility,
RenderFrameHost* fenced_frame_root);
// WebContentsObserver implementation.
void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) override;
void OnFrameVisibilityChanged(
RenderFrameHost* rfh,
blink::mojom::FrameVisibility visibility) override;
void Wait();
private:
blink::mojom::FrameVisibility target_visibility_ =
blink::mojom::FrameVisibility::kNotRendered;
raw_ptr<RenderFrameHost> fenced_frame_root_;
base::RunLoop run_loop_;
};
// Creates a fenced frame and waits for it to be rendered in the viewport.
// If `url` is provided, also navigates the fenced frame to the provided URL,
// and waits for it to load successfully. Returns the root RenderFrameHost of
// the fenced frame's inner FrameTree.
RenderFrameHost* CreateFencedFrameAndWaitUntilRenderedInViewport(
RenderFrameHost* parent_rfh,
base::optional_ref<const GURL> url);
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Maps a URL to a URN that can be loaded into an opaque-ads fenced frame. This
// can be called from outside of `content/` as it does not require access to
// `RenderFrameHostImpl`.
GURL CreateFencedFrameURLMapping(RenderFrameHost* rfh, const GURL& url);
// Helper function that converts a URL to a URN and adds the mapping to a given
// fenced frame URL mapping object. This can only be called from inside of
// `content/`.
GURL AddAndVerifyFencedFrameURL(
FencedFrameURLMapping* fenced_frame_url_mapping,
const GURL& https_url,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter = nullptr);
// Revoke the fenced frame untrusted network access.
bool RevokeFencedFrameUntrustedNetwork(RenderFrameHost* rfh);
// Exempt the `urls` from fenced frame untrusted network revocation.
void ExemptUrlsFromFencedFrameNetworkRevocation(RenderFrameHost* rfh,
const std::vector<GURL>& urls);
// Create and set fenced frame config to map to the given URL.
void SetFencedFrameConfig(RenderFrameHost* rfh, const GURL& url);
// Simulate a mouse click at the `point` inside fenced frame tree.
//
// Note: if the click is inside a nested iframe which is same-site with the
// root fenced frame, the coordinates of `point` need to be offset by the
// top-left coordinates of the nested iframe relative to the fenced frame. See
// `GetTopLeftCoordinatesOfElementWithId`. This is because the same-site nested
// iframe does not have a `RenderWidgetHost`. The mouse event is forwarded to
// the `RenderWidgetHost` of the fenced frame even if the nested iframe
// `RenderFrameHost` is passed in.
//
// However, a cross-site nested iframe becomes an OOPIF in fenced frame tree and
// gets its own `RenderWidgetHost`. There is no need to offset the coordinates.
//
// Note: If the simulation does not take place inside a fenced frame tree,
// use `SimulateMouseClickAt` in `content/public/test/browser_test_utils.h`.
void SimulateClickInFencedFrameTree(const ToRenderFrameHost& adapter,
blink::WebMouseEvent::Button button,
const gfx::PointF& point);
// Get the top left coordinates of the element with `id`, relative to `adapter`.
gfx::PointF GetTopLeftCoordinatesOfElementWithId(
const ToRenderFrameHost& adapter,
std::string_view id);
} // namespace test
} // namespace content
#endif // CONTENT_PUBLIC_TEST_FENCED_FRAME_TEST_UTIL_H_