// 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.
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "content/public/test/browser_test.h"
#include "fuchsia_web/common/test/frame_for_test.h"
#include "fuchsia_web/common/test/frame_test_util.h"
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/webengine/browser/frame_impl_browser_test_base.h"
namespace {
constexpr char kPage1Path[] = "/title1.html";
constexpr char kPage2Path[] = "/title2.html";
constexpr char kPage1Title[] = "title 1";
constexpr char kPopupParentPath[] = "/popup_parent.html";
constexpr char kPopupRedirectPath[] = "/popup_child.html";
constexpr char kPopupMultiplePath[] = "/popup_multiple.html";
constexpr char kChildQueryParamName[] = "child_url";
constexpr char kPopupChildFile[] = "popup_child.html";
constexpr char kAutoplayFileAndQuery[] =
"play_video.html?autoplay=1&codecs=vp8";
constexpr char kAutoPlayBlockedTitle[] = "blocked";
constexpr char kAutoPlaySuccessTitle[] = "playing";
class TestPopupListener : public fuchsia::web::PopupFrameCreationListener {
public:
TestPopupListener() = default;
~TestPopupListener() override = default;
TestPopupListener(const TestPopupListener&) = delete;
TestPopupListener& operator=(const TestPopupListener&) = delete;
void GetAndAckNextPopup(fuchsia::web::FramePtr* frame,
fuchsia::web::PopupFrameCreationInfo* creation_info) {
if (!frame_) {
base::RunLoop run_loop;
received_popup_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
*frame = frame_.Bind();
*creation_info = std::move(creation_info_);
popup_ack_callback_();
popup_ack_callback_ = {};
}
private:
void OnPopupFrameCreated(fidl::InterfaceHandle<fuchsia::web::Frame> frame,
fuchsia::web::PopupFrameCreationInfo creation_info,
OnPopupFrameCreatedCallback callback) override {
creation_info_ = std::move(creation_info);
frame_ = std::move(frame);
popup_ack_callback_ = std::move(callback);
if (received_popup_callback_)
std::move(received_popup_callback_).Run();
}
fidl::InterfaceHandle<fuchsia::web::Frame> frame_;
fuchsia::web::PopupFrameCreationInfo creation_info_;
base::OnceClosure received_popup_callback_;
OnPopupFrameCreatedCallback popup_ack_callback_;
};
class PopupTest : public FrameImplTestBaseWithServer {
public:
PopupTest()
: popup_listener_binding_(&popup_listener_),
popup_nav_listener_binding_(&popup_nav_listener_) {}
~PopupTest() override = default;
PopupTest(const PopupTest&) = delete;
PopupTest& operator=(const PopupTest&) = delete;
protected:
// Builds a URL for the kPopupParentPath page to pop up a Frame with
// |child_file_and_query|. |child_file_and_query| may optionally include a
// query string.
GURL GetParentPageTestServerUrl(const char* child) const {
const std::string url = base::StringPrintf("%s?%s=%s", kPopupParentPath,
kChildQueryParamName, child);
return embedded_test_server()->GetURL(url);
}
// Loads a page that autoplays video in a popup, populates the popup_*
// members, and returns its URL.
GURL LoadAutoPlayingPageInPopup(
fuchsia::web::AutoplayPolicy autoplay_policy) {
GURL popup_parent_url = GetParentPageTestServerUrl(kAutoplayFileAndQuery);
GURL popup_child_url = embedded_test_server()->GetURL(
base::StringPrintf("/%s", kAutoplayFileAndQuery));
auto parent_frame = FrameForTest::Create(context(), {});
// Set `autoplay_policy` for the parent frame. It should be inherited by the
// popup.
fuchsia::web::ContentAreaSettings settings;
settings.set_autoplay_policy(autoplay_policy);
parent_frame->SetContentAreaSettings(std::move(settings));
parent_frame->SetPopupFrameCreationListener(
popup_listener_binding_.NewBinding());
EXPECT_TRUE(LoadUrlAndExpectResponse(parent_frame.GetNavigationController(),
{}, popup_parent_url.spec()));
fuchsia::web::PopupFrameCreationInfo popup_info;
popup_listener_.GetAndAckNextPopup(&popup_frame_, &popup_info);
EXPECT_EQ(popup_info.initial_url(), popup_child_url);
popup_frame_->SetNavigationEventListener2(
popup_nav_listener_binding_.NewBinding(), /*flags=*/{});
return popup_child_url;
}
fuchsia::web::FramePtr popup_frame_;
TestPopupListener popup_listener_;
fidl::Binding<fuchsia::web::PopupFrameCreationListener>
popup_listener_binding_;
TestNavigationListener popup_nav_listener_;
fidl::Binding<fuchsia::web::NavigationEventListener>
popup_nav_listener_binding_;
};
IN_PROC_BROWSER_TEST_F(PopupTest, PopupWindowRedirect) {
GURL popup_parent_url = GetParentPageTestServerUrl(kPopupChildFile);
GURL popup_child_url(embedded_test_server()->GetURL(kPopupRedirectPath));
GURL title1_url(embedded_test_server()->GetURL(kPage1Path));
auto frame = FrameForTest::Create(context(), {});
frame->SetPopupFrameCreationListener(popup_listener_binding_.NewBinding());
EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(), {},
popup_parent_url.spec()));
// Verify the popup's initial URL, "popup_child.html".
fuchsia::web::PopupFrameCreationInfo popup_info;
popup_listener_.GetAndAckNextPopup(&popup_frame_, &popup_info);
EXPECT_EQ(popup_info.initial_url(), popup_child_url);
// Verify that the popup eventually redirects to "title1.html".
popup_frame_->SetNavigationEventListener2(
popup_nav_listener_binding_.NewBinding(), /*flags=*/{});
popup_nav_listener_.RunUntilUrlAndTitleEquals(title1_url, kPage1Title);
}
IN_PROC_BROWSER_TEST_F(PopupTest, MultiplePopups) {
GURL popup_parent_url(embedded_test_server()->GetURL(kPopupMultiplePath));
GURL title1_url(embedded_test_server()->GetURL(kPage1Path));
GURL title2_url(embedded_test_server()->GetURL(kPage2Path));
auto frame = FrameForTest::Create(context(), {});
frame->SetPopupFrameCreationListener(popup_listener_binding_.NewBinding());
EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(), {},
popup_parent_url.spec()));
fuchsia::web::PopupFrameCreationInfo popup_info;
popup_listener_.GetAndAckNextPopup(&popup_frame_, &popup_info);
EXPECT_EQ(popup_info.initial_url(), title1_url);
popup_listener_.GetAndAckNextPopup(&popup_frame_, &popup_info);
EXPECT_EQ(popup_info.initial_url(), title2_url);
}
// Verifies that the child popup Frame has the same default CreateFrameParams as
// the parent Frame by verifying that autoplay is blocked in the child. This
// mostly verifies that AutoPlaySucceedsis actually modifies behavior.
IN_PROC_BROWSER_TEST_F(PopupTest,
PopupFrameHasSameContentAreaSettings_AutoplayBlocked) {
// Load the page and wait for the popup Frame to be created.
GURL popup_child_url = LoadAutoPlayingPageInPopup(
fuchsia::web::AutoplayPolicy::REQUIRE_USER_ACTIVATION);
// Verify that the child does not autoplay media.
popup_nav_listener_.RunUntilUrlAndTitleEquals(popup_child_url,
kAutoPlayBlockedTitle);
}
// Verifies that the child popup Frame has the same CreateFrameParams as the
// parent Frame by allowing autoplay in the parent's params and verifying that
// autoplay succeeds in the child.
IN_PROC_BROWSER_TEST_F(PopupTest,
PopupFrameHasSameContentAreaSettings_AutoplaySucceeds) {
// Load the page and wait for the popup Frame to be created.
GURL popup_child_url =
LoadAutoPlayingPageInPopup(fuchsia::web::AutoplayPolicy::ALLOW);
// Verify that the child autoplays media.
popup_nav_listener_.RunUntilUrlAndTitleEquals(popup_child_url,
kAutoPlaySuccessTitle);
}
} // namespace