blob: b66c60fed627d92a2e74f54ce2c9bbf2ac85a7dc [file] [log] [blame]
// 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.
#include "chrome/browser/controlled_frame/scoped_test_driver_proxy.h"
#include <optional>
#include <string>
#include "base/check.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_devtools_protocol_client.h"
namespace controlled_frame {
namespace {
void HandleSetPermission(content::TestDevToolsProtocolClient& devtools_client,
const base::Value::Dict& arguments) {
const std::string* name = arguments.FindString("name");
const std::string* state = arguments.FindString("state");
const std::string* origin = arguments.FindString("origin");
CHECK(name && state) << "Invalid set_permission arguments: " << arguments;
base::Value::Dict args;
args.Set("permission", base::Value::Dict().Set("name", *name));
args.Set("setting", *state);
if (origin) {
args.Set("origin", *origin);
}
devtools_client.SendCommandSync("Browser.setPermission", std::move(args));
}
} // namespace
ScopedTestDriverProxy::ScopedTestDriverProxy(
content::RenderFrameHost* render_frame_host)
: render_frame_host_(render_frame_host), message_queue_(render_frame_host) {
devtools_client_.AttachToWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host));
HandleMessages();
}
ScopedTestDriverProxy::~ScopedTestDriverProxy() {
devtools_client_.DetachProtocolClient();
}
// static
const char* ScopedTestDriverProxy::testdriver_override_script_src() {
return R"(
(function() {
function sendMessage(actionName, arguments) {
const nonce = `cb${Math.random().toString(16).slice(2)}`;
return new Promise((resolve) => {
window[nonce] = resolve;
domAutomationController.send({
action: actionName,
callback: `window.${nonce}()`,
arguments,
});
});
}
window.test_driver_internal.set_permission =
function(permission_params, context) {
return sendMessage('set_permission', {
name: permission_params.descriptor.name,
state: permission_params.state,
origin: context?.origin
});
};
})())";
}
void ScopedTestDriverProxy::HandleMessages() {
while (message_queue_.HasMessages()) {
std::string message_json;
CHECK(message_queue_.PopMessage(&message_json));
std::optional<base::Value::Dict> message =
base::JSONReader::ReadDict(message_json);
if (!message.has_value()) {
LOG(ERROR) << "Invalid message from domAutomationController: "
<< message_json;
continue;
}
std::string* action = message->FindString("action");
std::string* callback = message->FindString("callback");
base::Value::Dict* arguments = message->FindDict("arguments");
if (!action || !callback || !arguments) {
LOG(ERROR) << "Invalid message from domAutomationController: "
<< message_json;
continue;
}
if (*action == "set_permission") {
HandleSetPermission(devtools_client_, *arguments);
}
CHECK(content::ExecJs(render_frame_host_, *callback));
}
message_queue_.SetOnMessageAvailableCallback(base::BindOnce(
&ScopedTestDriverProxy::HandleMessages, base::Unretained(this)));
}
} // namespace controlled_frame