blob: adf9ac19af718a67f0be1da47db7ac06d4e8dd90 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/shell/test_runner/web_frame_test_proxy.h"
#include "content/common/unique_name_helper.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/shell/renderer/web_test/blink_test_runner.h"
#include "content/shell/test_runner/test_interfaces.h"
#include "content/shell/test_runner/test_runner.h"
#include "content/shell/test_runner/web_frame_test_client.h"
#include "content/shell/test_runner/web_view_test_proxy.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/blink/public/web/web_view.h"
namespace content {
namespace {
void PrintFrameUserGestureStatus(BlinkTestRunner* blink_test_runner,
blink::WebLocalFrame* frame,
const char* msg) {
bool is_user_gesture = frame->HasTransientUserActivation();
blink_test_runner->PrintMessage(std::string("Frame with user gesture \"") +
(is_user_gesture ? "true" : "false") + "\"" +
msg);
}
class TestRenderFrameObserver : public content::RenderFrameObserver {
public:
TestRenderFrameObserver(content::RenderFrame* frame, WebViewTestProxy* proxy)
: RenderFrameObserver(frame), web_view_test_proxy_(proxy) {}
~TestRenderFrameObserver() override {}
private:
TestRunner* test_runner() {
return web_view_test_proxy_->test_interfaces()->GetTestRunner();
}
BlinkTestRunner* blink_test_runner() {
return web_view_test_proxy_->blink_test_runner();
}
// content::RenderFrameObserver overrides.
void OnDestruct() override { delete this; }
void DidStartNavigation(
const GURL& url,
base::Optional<blink::WebNavigationType> navigation_type) override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - DidStartNavigation\n");
}
if (test_runner()->ShouldDumpUserGestureInFrameLoadCallbacks()) {
PrintFrameUserGestureStatus(blink_test_runner(),
render_frame()->GetWebFrame(),
" - in DidStartNavigation\n");
}
}
void ReadyToCommitNavigation(
blink::WebDocumentLoader* document_loader) override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - ReadyToCommitNavigation\n");
}
}
void DidCommitProvisionalLoad(bool is_same_document_navigation,
ui::PageTransition transition) override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - didCommitLoadForFrame\n");
}
// Looking for navigations to about:blank after a test completes.
if (render_frame()->IsMainFrame() && !is_same_document_navigation) {
render_frame()->GetRenderView()->GetWebView()->SetFocusedFrame(
render_frame()->GetWebFrame());
blink_test_runner()->DidCommitNavigationInMainFrame();
}
}
void DidFailProvisionalLoad() override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - didFailProvisionalLoadWithError\n");
}
}
void DidFinishDocumentLoad() override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - didFinishDocumentLoadForFrame\n");
}
}
void DidFinishLoad() override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - didFinishLoadForFrame\n");
}
}
void DidHandleOnloadEvents() override {
if (test_runner()->ShouldDumpFrameLoadCallbacks()) {
std::string description = WebFrameTestClient::GetFrameDescription(
render_frame()->GetWebFrame());
blink_test_runner()->PrintMessage(description +
" - didHandleOnloadEventsForFrame\n");
}
}
WebViewTestProxy* web_view_test_proxy_;
DISALLOW_COPY_AND_ASSIGN(TestRenderFrameObserver);
};
} // namespace
WebFrameTestProxy::WebFrameTestProxy(RenderFrameImpl::CreateParams params)
: RenderFrameImpl(std::move(params)),
web_view_test_proxy_(static_cast<WebViewTestProxy*>(render_view())),
test_client_(web_view_test_proxy_, this) {}
WebFrameTestProxy::~WebFrameTestProxy() = default;
void WebFrameTestProxy::Initialize() {
RenderFrameImpl::Initialize();
test_client_.Initialize();
GetAssociatedInterfaceRegistry()->AddInterface(
base::BindRepeating(&WebFrameTestProxy::BindReceiver,
// The registry goes away and stops using this
// callback when RenderFrameImpl (which is this class)
// is destroyed.
base::Unretained(this)));
new TestRenderFrameObserver(this, web_view_test_proxy_); // deletes itself.
}
void WebFrameTestProxy::Reset() {
// TODO(crbug.com/936696): The RenderDocument project will cause us to replace
// the main frame on each navigation, including to about:blank and then to the
// next test. So resetting the frame or RenderWidget won't be meaningful then.
if (IsMainFrame()) {
GetWebFrame()->SetName(blink::WebString());
GetWebFrame()->ClearOpener();
blink::WebTestingSupport::ResetInternalsObject(GetWebFrame());
// Resetting the internals object also overrides the WebPreferences, so we
// have to sync them to WebKit again.
render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
}
if (IsLocalRoot()) {
GetLocalRootWebWidgetTestProxy()->Reset();
GetLocalRootWebWidgetTestProxy()->EndSyntheticGestures();
}
test_client_.Reset();
}
std::string WebFrameTestProxy::GetFrameNameForWebTests() {
return content::UniqueNameHelper::ExtractStableNameForTesting(unique_name());
}
void WebFrameTestProxy::UpdateAllLifecyclePhasesAndCompositeForTesting() {
if (!IsLocalRoot())
return;
auto* widget = static_cast<WebWidgetTestProxy*>(GetLocalRootRenderWidget());
widget->SynchronouslyComposite(/*do_raster=*/true);
}
// WebLocalFrameClient implementation.
blink::WebPlugin* WebFrameTestProxy::CreatePlugin(
const blink::WebPluginParams& params) {
blink::WebPlugin* plugin = test_client_.CreatePlugin(params);
if (plugin)
return plugin;
return RenderFrameImpl::CreatePlugin(params);
}
void WebFrameTestProxy::DidAddMessageToConsole(
const blink::WebConsoleMessage& message,
const blink::WebString& source_name,
unsigned source_line,
const blink::WebString& stack_trace) {
test_client_.DidAddMessageToConsole(message, source_name, source_line,
stack_trace);
RenderFrameImpl::DidAddMessageToConsole(message, source_name, source_line,
stack_trace);
}
void WebFrameTestProxy::DidStartLoading() {
test_client_.DidStartLoading();
RenderFrameImpl::DidStartLoading();
}
void WebFrameTestProxy::DidStopLoading() {
RenderFrameImpl::DidStopLoading();
test_client_.DidStopLoading();
}
void WebFrameTestProxy::DidChangeSelection(bool is_selection_empty) {
test_client_.DidChangeSelection(is_selection_empty);
RenderFrameImpl::DidChangeSelection(is_selection_empty);
}
void WebFrameTestProxy::DidChangeContents() {
test_client_.DidChangeContents();
RenderFrameImpl::DidChangeContents();
}
blink::WebEffectiveConnectionType
WebFrameTestProxy::GetEffectiveConnectionType() {
if (test_client_.GetEffectiveConnectionType() !=
blink::WebEffectiveConnectionType::kTypeUnknown) {
return test_client_.GetEffectiveConnectionType();
}
return RenderFrameImpl::GetEffectiveConnectionType();
}
void WebFrameTestProxy::ShowContextMenu(
const blink::WebContextMenuData& context_menu_data) {
test_client_.ShowContextMenu(context_menu_data);
RenderFrameImpl::ShowContextMenu(context_menu_data);
}
void WebFrameTestProxy::DidDispatchPingLoader(const blink::WebURL& url) {
// This is not implemented in RenderFrameImpl, so need to explicitly call
// into the base proxy.
test_client_.DidDispatchPingLoader(url);
RenderFrameImpl::DidDispatchPingLoader(url);
}
void WebFrameTestProxy::WillSendRequest(blink::WebURLRequest& request) {
RenderFrameImpl::WillSendRequest(request);
test_client_.WillSendRequest(request);
}
void WebFrameTestProxy::BeginNavigation(
std::unique_ptr<blink::WebNavigationInfo> info) {
if (test_client_.ShouldContinueNavigation(info.get()))
RenderFrameImpl::BeginNavigation(std::move(info));
}
void WebFrameTestProxy::PostAccessibilityEvent(const ui::AXEvent& event) {
test_client_.PostAccessibilityEvent(event);
RenderFrameImpl::PostAccessibilityEvent(event);
}
void WebFrameTestProxy::MarkWebAXObjectDirty(const blink::WebAXObject& object,
bool subtree) {
test_client_.MarkWebAXObjectDirty(object, subtree);
// Guard against the case where |this| was deleted as a result of an
// accessibility listener detaching a frame. If that occurs, the
// WebAXObject will be detached.
if (object.IsDetached())
return; // |this| is invalid.
RenderFrameImpl::MarkWebAXObjectDirty(object, subtree);
}
void WebFrameTestProxy::CheckIfAudioSinkExistsAndIsAuthorized(
const blink::WebString& sink_id,
blink::WebSetSinkIdCompleteCallback completion_callback) {
test_client_.CheckIfAudioSinkExistsAndIsAuthorized(
sink_id, std::move(completion_callback));
}
void WebFrameTestProxy::DidClearWindowObject() {
test_client_.DidClearWindowObject();
blink::WebTestingSupport::InjectInternalsObject(GetWebFrame());
RenderFrameImpl::DidClearWindowObject();
}
WebWidgetTestProxy* WebFrameTestProxy::GetLocalRootWebWidgetTestProxy() {
return static_cast<WebWidgetTestProxy*>(GetLocalRootRenderWidget());
}
void WebFrameTestProxy::CaptureDump(CaptureDumpCallback callback) {
blink_test_runner()->CaptureDump(std::move(callback));
}
void WebFrameTestProxy::CompositeWithRaster(
CompositeWithRasterCallback callback) {
// When the TestFinished() occurred, if the browser is capturing pixels, it
// asks each composited RenderFrame to submit a new frame via here.
UpdateAllLifecyclePhasesAndCompositeForTesting();
std::move(callback).Run();
}
void WebFrameTestProxy::DumpFrameLayout(DumpFrameLayoutCallback callback) {
TestInterfaces* interfaces = web_view_test_proxy_->test_interfaces();
TestRunner* test_runner = interfaces->GetTestRunner();
std::string dump = test_runner->DumpLayout(GetWebFrame());
std::move(callback).Run(std::move(dump));
}
void WebFrameTestProxy::ReplicateTestConfiguration(
mojom::ShellTestConfigurationPtr config) {
blink_test_runner()->OnReplicateTestConfiguration(std::move(config));
}
void WebFrameTestProxy::SetTestConfiguration(
mojom::ShellTestConfigurationPtr config) {
blink_test_runner()->OnSetTestConfiguration(std::move(config));
}
void WebFrameTestProxy::SetupRendererProcessForNonTestWindow() {
blink_test_runner()->OnSetupRendererProcessForNonTestWindow();
}
void WebFrameTestProxy::ResetRendererAfterWebTest() {
blink_test_runner()->OnResetRendererAfterWebTest();
}
void WebFrameTestProxy::FinishTestInMainWindow() {
blink_test_runner()->OnFinishTestInMainWindow();
}
void WebFrameTestProxy::LayoutDumpCompleted(
const std::string& completed_layout_dump) {
blink_test_runner()->OnLayoutDumpCompleted(completed_layout_dump);
}
void WebFrameTestProxy::ReplyBluetoothManualChooserEvents(
const std::vector<std::string>& events) {
blink_test_runner()->OnReplyBluetoothManualChooserEvents(events);
}
void WebFrameTestProxy::BindReceiver(
mojo::PendingAssociatedReceiver<mojom::BlinkTestControl> receiver) {
blink_test_control_receiver_.Bind(
std::move(receiver),
GetWebFrame()->GetTaskRunner(blink::TaskType::kInternalTest));
}
BlinkTestRunner* WebFrameTestProxy::blink_test_runner() {
return web_view_test_proxy_->blink_test_runner();
}
} // namespace content