Rewrite tests for blocking of popup windows in JS framework
These were the only tests that required the native network interceptor, so it's gone now. Change-Id: I06d6c2fd8a57c68654a075b308bd95c600b24ef2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6015099 Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Reviewed-by: Peter Kvitek <kvitekp@chromium.org> Cr-Commit-Position: refs/heads/main@{#1382590}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f5c0373f9f
commit
e520b5485b
@ -620,8 +620,6 @@ test("headless_browsertests") {
|
||||
"test/headless_origin_trials_browsertest.cc",
|
||||
"test/headless_test_launcher.cc",
|
||||
"test/headless_web_contents_browsertest.cc",
|
||||
"test/test_network_interceptor.cc",
|
||||
"test/test_network_interceptor.h",
|
||||
]
|
||||
|
||||
if (enable_printing && enable_pdf) {
|
||||
|
@ -106,6 +106,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of requested URLs.
|
||||
*
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
requestedUrls() {
|
||||
return this.requestedUrls_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if specified urls have been requested.
|
||||
*
|
||||
|
@ -0,0 +1,2 @@
|
||||
Tests pop ups can be blocked.
|
||||
PASS
|
53
headless/test/data/protocol/sanity/popup-window-open.js
Normal file
53
headless/test/data/protocol/sanity/popup-window-open.js
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
(async function(testRunner) {
|
||||
const {session, dp} = await testRunner.startBlank(
|
||||
'Tests pop ups can be blocked.');
|
||||
|
||||
const {sessionId} =
|
||||
(await testRunner.browserP().Target.attachToBrowserTarget({})).result;
|
||||
const bp = (new TestRunner.Session(testRunner, sessionId)).protocol;
|
||||
|
||||
const HttpInterceptor = await testRunner.loadScript(
|
||||
'../helpers/http-interceptor.js');
|
||||
const httpInterceptor = await (new HttpInterceptor(testRunner, bp)).init();
|
||||
|
||||
httpInterceptor.setDisableRequestedUrlsLogging(true);
|
||||
httpInterceptor.addResponse('http://example.com/index.html', `
|
||||
<script>
|
||||
const win = window.open('/page2.html');
|
||||
if (!win) {
|
||||
console.error('ready');
|
||||
}
|
||||
win.addEventListener('load', () => console.log('ready'));
|
||||
</script>`);
|
||||
|
||||
httpInterceptor.addResponse('http://example.com/page2.html',
|
||||
`<body>Page 2</body>`);
|
||||
|
||||
dp.Runtime.enable();
|
||||
const readyPromise = dp.Runtime.onceConsoleAPICalled();
|
||||
session.navigate('http://example.com/index.html');
|
||||
|
||||
const message = (await readyPromise).params.args[0].value;
|
||||
if (message !== 'ready') {
|
||||
testRunner.fail(`Unexpected console message: ${message}`);
|
||||
}
|
||||
const requestedUrls = new Set(httpInterceptor.requestedUrls());
|
||||
if (!requestedUrls.has('http://example.com/index.html')) {
|
||||
testRunner.fail('Main page not requested');
|
||||
}
|
||||
const seenPopupRequest = requestedUrls.has(
|
||||
'http://example.com/page2.html');
|
||||
if (seenPopupRequest === !testRunner.params('blockingNewWebContents')) {
|
||||
testRunner.log('PASS');
|
||||
} else {
|
||||
const message = seenPopupRequest ? 'Popup blocked but requested'
|
||||
: 'Popup not blocked but not requested';
|
||||
testRunner.log(Array.from(requestedUrls), `FAIL: ${message}: `);
|
||||
}
|
||||
|
||||
testRunner.completeTest();
|
||||
})
|
@ -22,6 +22,8 @@
|
||||
#include "headless/test/headless_browser_test_utils.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
#include "services/network/public/cpp/network_switches.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/switches.h"
|
||||
|
||||
namespace headless {
|
||||
@ -238,6 +240,13 @@ void HeadlessProtocolBrowserTest::FinishTest() {
|
||||
HEADLESS_PROTOCOL_TEST_CLASS(HeadlessProtocolBrowserTest, TEST_NAME, \
|
||||
SCRIPT_NAME)
|
||||
|
||||
#define HEADLESS_PROTOCOL_TEST_P(CLASS_NAME, TEST_NAME, SCRIPT_NAME) \
|
||||
IN_PROC_BROWSER_TEST_P(CLASS_NAME, TEST_NAME) { \
|
||||
test_folder_ = "/protocol/"; \
|
||||
script_name_ = SCRIPT_NAME; \
|
||||
RunTest(); \
|
||||
}
|
||||
|
||||
// Headless-specific tests
|
||||
HEADLESS_PROTOCOL_TEST(VirtualTimeBasics, "emulation/virtual-time-basics.js")
|
||||
HEADLESS_PROTOCOL_TEST(VirtualTimeInterrupt,
|
||||
@ -471,6 +480,33 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
|
||||
HEADLESS_DEVTOOLED_TEST_P(HeadlessAllowedVideoCodecsTest);
|
||||
|
||||
class PopupWindowOpenTest : public HeadlessProtocolBrowserTest,
|
||||
public testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
PopupWindowOpenTest() = default;
|
||||
|
||||
void CustomizeHeadlessBrowserContext(
|
||||
HeadlessBrowserContext::Builder& builder) override {
|
||||
builder.SetBlockNewWebContents(ShouldBlockNewWebContents());
|
||||
}
|
||||
|
||||
base::Value::Dict GetPageUrlExtraParams() override {
|
||||
base::Value::Dict params;
|
||||
params.Set("blockingNewWebContents", ShouldBlockNewWebContents());
|
||||
return params;
|
||||
}
|
||||
|
||||
bool ShouldBlockNewWebContents() const { return GetParam(); }
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(/* no prefix */,
|
||||
PopupWindowOpenTest,
|
||||
::testing::Bool());
|
||||
|
||||
HEADLESS_PROTOCOL_TEST_P(PopupWindowOpenTest,
|
||||
Open,
|
||||
"sanity/popup-window-open.js")
|
||||
|
||||
class HeadlessProtocolBrowserTestWithoutSiteIsolation
|
||||
: public HeadlessProtocolBrowserTest {
|
||||
public:
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "headless/test/headless_browser_test.h"
|
||||
#include "headless/test/headless_browser_test_utils.h"
|
||||
#include "headless/test/headless_devtooled_browsertest.h"
|
||||
#include "headless/test/test_network_interceptor.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/switches.h"
|
||||
@ -628,94 +627,6 @@ class CookiesEnabled : public HeadlessDevTooledBrowserTest {
|
||||
|
||||
HEADLESS_DEVTOOLED_TEST_F(CookiesEnabled);
|
||||
|
||||
namespace {
|
||||
const char* kPageWhichOpensAWindow = R"(
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
const win = window.open('/page2.html');
|
||||
if (!win)
|
||||
console.error('ready');
|
||||
win.addEventListener('load', () => console.log('ready'));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
const char* kPage2 = R"(
|
||||
<html>
|
||||
<body>
|
||||
Page 2.
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
} // namespace
|
||||
|
||||
class WebContentsOpenTest : public HeadlessDevTooledBrowserTest {
|
||||
public:
|
||||
void PreRunAsynchronousTest() override {
|
||||
interceptor_ = std::make_unique<TestNetworkInterceptor>();
|
||||
}
|
||||
|
||||
void PostRunAsynchronousTest() override { interceptor_.reset(); }
|
||||
|
||||
void RunDevTooledTest() override {
|
||||
DCHECK(interceptor_);
|
||||
|
||||
interceptor_->InsertResponse("http://foo.com/index.html",
|
||||
{kPageWhichOpensAWindow, "text/html"});
|
||||
interceptor_->InsertResponse("http://foo.com/page2.html",
|
||||
{kPage2, "text/html"});
|
||||
|
||||
devtools_client_.AddEventHandler(
|
||||
"Runtime.consoleAPICalled",
|
||||
base::BindRepeating(&WebContentsOpenTest::OnConsoleAPICalled,
|
||||
base::Unretained(this)));
|
||||
SendCommandSync(devtools_client_, "Runtime.enable");
|
||||
|
||||
devtools_client_.SendCommand("Page.navigate",
|
||||
Param("url", "http://foo.com/index.html"));
|
||||
}
|
||||
|
||||
virtual void OnConsoleAPICalled(const base::Value::Dict& params) {}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<TestNetworkInterceptor> interceptor_;
|
||||
};
|
||||
|
||||
class DontBlockWebContentsOpenTest : public WebContentsOpenTest {
|
||||
public:
|
||||
void CustomizeHeadlessBrowserContext(
|
||||
HeadlessBrowserContext::Builder& builder) override {
|
||||
builder.SetBlockNewWebContents(false);
|
||||
}
|
||||
|
||||
void OnConsoleAPICalled(const base::Value::Dict& params) override {
|
||||
EXPECT_THAT(
|
||||
interceptor_->urls_requested(),
|
||||
ElementsAre("http://foo.com/index.html", "http://foo.com/page2.html"));
|
||||
FinishAsynchronousTest();
|
||||
}
|
||||
};
|
||||
|
||||
HEADLESS_DEVTOOLED_TEST_F(DontBlockWebContentsOpenTest);
|
||||
|
||||
class BlockWebContentsOpenTest : public WebContentsOpenTest {
|
||||
public:
|
||||
void CustomizeHeadlessBrowserContext(
|
||||
HeadlessBrowserContext::Builder& builder) override {
|
||||
builder.SetBlockNewWebContents(true);
|
||||
}
|
||||
|
||||
void OnConsoleAPICalled(const base::Value::Dict& params) override {
|
||||
EXPECT_THAT(interceptor_->urls_requested(),
|
||||
ElementsAre("http://foo.com/index.html"));
|
||||
FinishAsynchronousTest();
|
||||
}
|
||||
};
|
||||
|
||||
HEADLESS_DEVTOOLED_TEST_F(BlockWebContentsOpenTest);
|
||||
|
||||
// Regression test for crbug.com/1385982.
|
||||
class BlockDevToolsEmbedding : public HeadlessDevTooledBrowserTest {
|
||||
protected:
|
||||
|
@ -1,196 +0,0 @@
|
||||
// Copyright 2018 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "headless/test/test_network_interceptor.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/url_request/redirect_info.h"
|
||||
#include "net/url_request/redirect_util.h"
|
||||
#include "services/network/public/mojom/url_loader.mojom.h"
|
||||
#include "services/network/public/mojom/url_response_head.mojom.h"
|
||||
|
||||
namespace headless {
|
||||
|
||||
namespace {
|
||||
|
||||
class RedirectLoader : public network::mojom::URLLoader {
|
||||
public:
|
||||
RedirectLoader(TestNetworkInterceptor::Impl* interceptor_impl,
|
||||
content::URLLoaderInterceptor::RequestParams* request,
|
||||
TestNetworkInterceptor::Response* response,
|
||||
const std::string& url)
|
||||
: interceptor_impl_(interceptor_impl),
|
||||
receiver_(this, std::move(request->receiver)),
|
||||
client_(std::move(request->client)),
|
||||
url_request_(request->url_request),
|
||||
response_(response),
|
||||
url_(request->url_request.url) {
|
||||
receiver_.set_disconnect_handler(
|
||||
base::BindOnce([](RedirectLoader* self) { delete self; }, this));
|
||||
NotifyRedirect(std::move(url));
|
||||
}
|
||||
|
||||
void FollowRedirect(
|
||||
const std::vector<std::string>& removed_headers,
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const net::HttpRequestHeaders& modified_cors_exempt_headers,
|
||||
const std::optional<GURL>& new_url) override;
|
||||
|
||||
void SetPriority(net::RequestPriority priority,
|
||||
int32_t intra_priority_value) override {}
|
||||
void PauseReadingBodyFromNet() override {}
|
||||
void ResumeReadingBodyFromNet() override {}
|
||||
|
||||
private:
|
||||
void NotifyRedirect(const std::string& location) {
|
||||
auto redirect_info = net::RedirectInfo::ComputeRedirectInfo(
|
||||
url_request_.method, url_request_.url, url_request_.site_for_cookies,
|
||||
net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT,
|
||||
url_request_.referrer_policy, url_request_.referrer.spec(),
|
||||
response_->headers->response_code(), url_.Resolve(location),
|
||||
net::RedirectUtil::GetReferrerPolicyHeader(response_->headers.get()),
|
||||
false /* insecure_scheme_was_upgraded */, true);
|
||||
auto head = network::mojom::URLResponseHead::New();
|
||||
head->request_time = base::Time::Now();
|
||||
head->response_time = base::Time::Now();
|
||||
head->content_length = 0;
|
||||
head->encoded_data_length = 0;
|
||||
head->headers = response_->headers;
|
||||
url_ = redirect_info.new_url;
|
||||
method_ = redirect_info.new_method;
|
||||
client_->OnReceiveRedirect(redirect_info, std::move(head));
|
||||
}
|
||||
|
||||
const raw_ptr<TestNetworkInterceptor::Impl> interceptor_impl_;
|
||||
|
||||
mojo::Receiver<network::mojom::URLLoader> receiver_;
|
||||
mojo::Remote<network::mojom::URLLoaderClient> client_;
|
||||
network::ResourceRequest url_request_;
|
||||
raw_ptr<TestNetworkInterceptor::Response> response_;
|
||||
GURL url_;
|
||||
std::string method_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class TestNetworkInterceptor::Impl {
|
||||
public:
|
||||
explicit Impl(base::WeakPtr<TestNetworkInterceptor> interceptor)
|
||||
: interceptor_(std::move(interceptor)) {}
|
||||
|
||||
void InsertResponse(std::string url, Response response) {
|
||||
response_map_.emplace(StripFragment(url),
|
||||
std::make_unique<Response>(std::move(response)));
|
||||
}
|
||||
|
||||
Response* FindResponse(const std::string& method, const std::string& url) {
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE, base::BindOnce(&TestNetworkInterceptor::LogRequest,
|
||||
interceptor_, method, url));
|
||||
auto it = response_map_.find(StripFragment(url));
|
||||
return it == response_map_.end() ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
bool RequestHandler(content::URLLoaderInterceptor::RequestParams* request) {
|
||||
Response* response = FindResponse(request->url_request.method,
|
||||
request->url_request.url.spec());
|
||||
if (!response)
|
||||
return false;
|
||||
|
||||
std::string location;
|
||||
if (response->headers->IsRedirect(&location)) {
|
||||
new RedirectLoader(this, request, response, location);
|
||||
return true;
|
||||
}
|
||||
content::URLLoaderInterceptor::WriteResponse(
|
||||
response->raw_headers, response->body, request->client.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string StripFragment(std::string url) {
|
||||
GURL::Replacements replacements;
|
||||
replacements.ClearRef();
|
||||
return GURL(url).ReplaceComponents(replacements).spec();
|
||||
}
|
||||
|
||||
std::map<std::string, std::unique_ptr<Response>> response_map_;
|
||||
base::WeakPtr<TestNetworkInterceptor> interceptor_;
|
||||
};
|
||||
|
||||
void RedirectLoader::FollowRedirect(
|
||||
const std::vector<std::string>& removed_headers /* unused */,
|
||||
const net::HttpRequestHeaders& modified_headers /* unused */,
|
||||
const net::HttpRequestHeaders& modified_cors_exempt_headers /* unused */,
|
||||
const std::optional<GURL>& new_url) {
|
||||
response_ = interceptor_impl_->FindResponse(method_, url_.spec());
|
||||
CHECK(response_) << "No content for " << url_.spec();
|
||||
std::string location;
|
||||
if (response_->headers->IsRedirect(&location)) {
|
||||
NotifyRedirect(location);
|
||||
return;
|
||||
}
|
||||
content::URLLoaderInterceptor::WriteResponse(response_->raw_headers,
|
||||
response_->body, client_.get());
|
||||
delete this;
|
||||
}
|
||||
|
||||
TestNetworkInterceptor::Response::Response(const std::string data) {
|
||||
static const char kHeaderDelimiter[] = "\r\n\r\n";
|
||||
size_t end_of_headers = data.find(kHeaderDelimiter);
|
||||
CHECK(end_of_headers != std::string::npos);
|
||||
raw_headers = data.substr(0, end_of_headers);
|
||||
body = data.substr(end_of_headers + strlen(kHeaderDelimiter));
|
||||
headers = base::MakeRefCounted<net::HttpResponseHeaders>(
|
||||
net::HttpUtil::AssembleRawHeaders(raw_headers));
|
||||
}
|
||||
|
||||
TestNetworkInterceptor::Response::Response(const std::string body,
|
||||
const std::string& mime_type)
|
||||
: raw_headers("HTTP/1.1 200 OK\r\nContent-Type: " + mime_type),
|
||||
body(std::move(body)) {
|
||||
headers = base::MakeRefCounted<net::HttpResponseHeaders>(
|
||||
net::HttpUtil::AssembleRawHeaders(raw_headers));
|
||||
}
|
||||
|
||||
TestNetworkInterceptor::Response::Response(const Response& r) = default;
|
||||
TestNetworkInterceptor::Response::Response(Response&& r) = default;
|
||||
|
||||
TestNetworkInterceptor::Response::~Response() {}
|
||||
|
||||
TestNetworkInterceptor::TestNetworkInterceptor() {
|
||||
impl_ = std::make_unique<Impl>(weak_factory_.GetWeakPtr());
|
||||
interceptor_ = std::make_unique<content::URLLoaderInterceptor>(
|
||||
base::BindRepeating(&TestNetworkInterceptor::Impl::RequestHandler,
|
||||
base::Unretained(impl_.get())));
|
||||
}
|
||||
|
||||
TestNetworkInterceptor::~TestNetworkInterceptor() {
|
||||
content::GetIOThreadTaskRunner({})->DeleteSoon(FROM_HERE, impl_.release());
|
||||
interceptor_.reset();
|
||||
}
|
||||
|
||||
void TestNetworkInterceptor::InsertResponse(std::string url,
|
||||
Response response) {
|
||||
content::GetIOThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&Impl::InsertResponse, base::Unretained(impl_.get()),
|
||||
std::move(url), std::move(response)));
|
||||
}
|
||||
|
||||
void TestNetworkInterceptor::LogRequest(std::string method, std::string url) {
|
||||
urls_requested_.emplace_back(std::move(url));
|
||||
methods_requested_.emplace_back(std::move(method));
|
||||
}
|
||||
|
||||
} // namespace headless
|
@ -1,65 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef HEADLESS_TEST_TEST_NETWORK_INTERCEPTOR_H_
|
||||
#define HEADLESS_TEST_TEST_NETWORK_INTERCEPTOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "content/public/test/url_loader_interceptor.h"
|
||||
|
||||
namespace headless {
|
||||
|
||||
class TestNetworkInterceptor {
|
||||
public:
|
||||
class Impl;
|
||||
|
||||
TestNetworkInterceptor();
|
||||
|
||||
TestNetworkInterceptor(const TestNetworkInterceptor&) = delete;
|
||||
TestNetworkInterceptor& operator=(const TestNetworkInterceptor&) = delete;
|
||||
|
||||
~TestNetworkInterceptor();
|
||||
|
||||
struct Response {
|
||||
Response() = delete;
|
||||
Response(const std::string data);
|
||||
Response(const std::string body, const std::string& mime_type);
|
||||
Response(const Response& r);
|
||||
Response(Response&& r);
|
||||
~Response();
|
||||
|
||||
scoped_refptr<net::HttpResponseHeaders> headers;
|
||||
std::string raw_headers;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
void InsertResponse(std::string url, Response response);
|
||||
|
||||
const std::vector<std::string>& urls_requested() const {
|
||||
return urls_requested_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& methods_requested() const {
|
||||
return methods_requested_;
|
||||
}
|
||||
|
||||
private:
|
||||
void LogRequest(std::string method, std::string url);
|
||||
|
||||
std::vector<std::string> urls_requested_;
|
||||
std::vector<std::string> methods_requested_;
|
||||
|
||||
std::unique_ptr<Impl> impl_;
|
||||
std::unique_ptr<content::URLLoaderInterceptor> interceptor_;
|
||||
|
||||
base::WeakPtrFactory<TestNetworkInterceptor> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace headless
|
||||
|
||||
#endif // HEADLESS_TEST_TEST_NETWORK_INTERCEPTOR_H_
|
Reference in New Issue
Block a user