#include "content/web_test/renderer/test_runner.h"
#include <stddef.h>
#include <algorithm>
#include <clocale>
#include <limits>
#include <utility>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/cxx20_erase.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/render_thread_impl.h"
#include "content/web_test/common/web_test_constants.h"
#include "content/web_test/common/web_test_string_util.h"
#include "content/web_test/renderer/app_banner_service.h"
#include "content/web_test/renderer/blink_test_helpers.h"
#include "content/web_test/renderer/fake_subresource_filter.h"
#include "content/web_test/renderer/pixel_dump.h"
#include "content/web_test/renderer/spell_check_client.h"
#include "content/web_test/renderer/test_preferences.h"
#include "content/web_test/renderer/web_frame_test_proxy.h"
#include "gin/arguments.h"
#include "gin/array_buffer.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
#include "mojo/public/mojom/base/text_direction.mojom-forward.h"
#include "net/base/filename_util.h"
#include "printing/page_range.h"
#include "services/network/public/mojom/cors.mojom.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/test/frame_widget_test_helper.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_array_buffer.h"
#include "third_party/blink/public/web/web_array_buffer_converter.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_document_loader.h"
#include "third_party/blink/public/web/web_element_collection.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_manifest_manager.h"
#include "third_party/blink/public/web/web_render_theme.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_security_policy.h"
#include "third_party/blink/public/web/web_serialized_script_value.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_view_observer.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/test/icc_profiles.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
#include "third_party/blink/public/platform/web_font_render_style.h"
#endif
namespace content {
namespace {
const int kWPTPrintWidth = 4 * 72;
const int kWPTPrintHeight = 2 * 72;
using BoundV8Callback =
base::OnceCallback<void(const std::vector<v8::Local<v8::Value>>&)>;
std::vector<v8::Local<v8::Value>> NoV8Args() {
return {};
}
std::vector<v8::Local<v8::Value>> ConvertBitmapToV8(
const v8::Context::Scope& context_scope,
const SkBitmap& bitmap) {
v8::Isolate* isolate = blink::MainThreadIsolate();
std::vector<v8::Local<v8::Value>> args;
args.push_back(v8::Number::New(isolate, bitmap.info().width()));
args.push_back(v8::Number::New(isolate, bitmap.info().height()));
if (bitmap.isNull()) {
return args;
}
SkImageInfo info = bitmap.info().makeColorType(kRGBA_8888_SkColorType);
size_t row_bytes = info.minRowBytes();
blink::WebArrayBuffer buffer =
blink::WebArrayBuffer::Create(info.computeByteSize(row_bytes), 1);
bool read = bitmap.readPixels(info, buffer.Data(), row_bytes, 0, 0);
CHECK(read);
args.push_back(blink::WebArrayBufferConverter::ToV8Value(
&buffer, isolate->GetCurrentContext()->Global(), isolate));
return args;
}
void ConvertAndSet(gin::Arguments* args, int* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
v8::Maybe<int> result = value->Int32Value(args->GetHolderCreationContext());
if (result.IsNothing()) {
args->Skip();
args->ThrowError();
return;
}
*set_param = result.ToChecked();
}
void ConvertAndSet(gin::Arguments* args, bool* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
*set_param = value->BooleanValue(args->isolate());
}
void ConvertAndSet(gin::Arguments* args, blink::WebString* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
v8::MaybeLocal<v8::String> result =
value->ToString(args->GetHolderCreationContext());
if (result.IsEmpty()) {
args->Skip();
args->ThrowError();
return;
}
*set_param = web_test_string_util::V8StringToWebString(
args->isolate(), result.ToLocalChecked());
}
}
class TestRunnerBindings : public gin::Wrappable<TestRunnerBindings> {
public:
static gin::WrapperInfo kWrapperInfo;
TestRunnerBindings(const TestRunnerBindings&) = delete;
TestRunnerBindings& operator=(const TestRunnerBindings&) = delete;
static void Install(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check,
bool is_wpt_reftest,
bool is_main_test_window);
BoundV8Callback WrapV8Callback(
v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args_to_bind = {});
base::OnceClosure WrapV8Closure(
v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args_to_bind = {});
void PostV8Callback(v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args = {});
blink::WebLocalFrame* GetWebFrame() {
CHECK(!invalid_);
return frame_->GetWebFrame();
}
private:
class TestRunnerBindingsRenderFrameObserver : public RenderFrameObserver {
public:
TestRunnerBindingsRenderFrameObserver(TestRunnerBindings* bindings,
RenderFrame* frame)
: RenderFrameObserver(frame), bindings_(bindings) {}
void OnDestruct() override { bindings_->OnFrameDestroyed(); }
private:
TestRunnerBindings* const bindings_;
};
explicit TestRunnerBindings(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check);
~TestRunnerBindings() override;
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
void AddOriginAccessAllowListEntry(const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains);
void AddWebPageOverlay();
void AllowPointerLock();
void SetHighlightAds();
#if BUILDFLAG(ENABLE_PRINTING)
void CapturePrintingPixelsThen(v8::Local<v8::Function> callback);
#endif
void CheckForLeakedWindows();
void ClearAllDatabases();
void ClearTrustTokenState(v8::Local<v8::Function> callback);
void CopyImageThen(int x, int y, v8::Local<v8::Function> callback);
void DisableMockScreenOrientation();
void DispatchBeforeInstallPromptEvent(
const std::vector<std::string>& event_platforms,
v8::Local<v8::Function> callback);
void DropPointerLock();
void DumpAsMarkup();
void DumpAsText();
void DumpAsTextWithPixelResults();
void DumpAsLayout();
void DumpAsLayoutWithPixelResults();
void DumpChildFrames();
void DumpBackForwardList();
void DumpCreateView();
void DumpDragImage();
void DumpEditingCallbacks();
void DumpFrameLoadCallbacks();
void DumpIconChanges();
void DumpNavigationPolicy();
void DumpPermissionClientCallbacks();
void DumpPingLoaderCallbacks();
void DumpSelectionRect();
void DumpTitleChanges();
void DumpUserGestureInFrameLoadCallbacks();
void EvaluateScriptInIsolatedWorld(int world_id, const std::string& script);
void ExecCommand(gin::Arguments* args);
void TriggerTestInspectorIssue(gin::Arguments* args);
void FocusDevtoolsSecondaryWindow();
void ForceNextDrawingBufferCreationToFail();
void ForceNextWebGLContextCreationToFail();
void GetBluetoothManualChooserEvents(v8::Local<v8::Function> callback);
void GetManifestThen(v8::Local<v8::Function> callback);
std::string GetWritableDirectory();
void InsertStyleSheet(const std::string& source_code);
void UpdateAllLifecyclePhasesAndComposite();
void UpdateAllLifecyclePhasesAndCompositeThen(
v8::Local<v8::Function> callback);
void SetAnimationRequiresRaster(bool do_raster);
void LogToStderr(const std::string& output);
void NotImplemented(const gin::Arguments& args);
void NotifyDone();
void OverridePreference(gin::Arguments* args);
void QueueBackNavigation(int how_far_back);
void QueueForwardNavigation(int how_far_forward);
void QueueLoad(gin::Arguments* args);
void QueueLoadingScript(const std::string& script);
void QueueNonLoadingScript(const std::string& script);
void QueueReload();
void RemoveSpellCheckResolvedCallback();
void RemoveWebPageOverlay();
void ResolveBeforeInstallPromptPromise(const std::string& platform);
void SendBluetoothManualChooserEvent(const std::string& event,
const std::string& argument);
void SetAcceptLanguages(const std::string& accept_languages);
void SetAllowFileAccessFromFileURLs(bool allow);
void SetAllowRunningOfInsecureContent(bool allowed);
void SetBlockThirdPartyCookies(bool block);
void SetAudioData(const gin::ArrayBufferView& view);
void SetBackingScaleFactor(double value, v8::Local<v8::Function> callback);
void SetBluetoothFakeAdapter(const std::string& adapter_name,
v8::Local<v8::Function> callback);
void SetBluetoothManualChooser(bool enable);
void SetBrowserHandlesFocus(bool enable);
void SetCaretBrowsingEnabled();
void SetColorProfile(const std::string& name,
v8::Local<v8::Function> callback);
void SetCustomPolicyDelegate(gin::Arguments* args);
void SetCustomTextOutput(const std::string& output);
void SetDatabaseQuota(int quota);
void SetDisallowedSubresourcePathSuffixes(std::vector<std::string> suffixes,
bool block_subresources);
void SetDomainRelaxationForbiddenForURLScheme(bool forbidden,
const std::string& scheme);
void SetDumpConsoleMessages(bool value);
void SetDumpJavaScriptDialogs(bool value);
void SetEffectiveConnectionType(const std::string& connection_type);
void SetFilePathForMockFileDialog(const std::string& path);
void SetMockSpellCheckerEnabled(bool enabled);
void SetImagesAllowed(bool allowed);
void SetIsolatedWorldInfo(int world_id,
v8::Local<v8::Value> security_origin,
v8::Local<v8::Value> content_security_policy);
void SetJavaScriptCanAccessClipboard(bool can_access);
void SetMockScreenOrientation(const std::string& orientation);
void SetPOSIXLocale(const std::string& locale);
void SetMainWindowHidden(bool hidden);
void SetPermission(const std::string& name,
const std::string& value,
const std::string& origin,
const std::string& embedding_origin);
void SetPluginsAllowed(bool allowed);
void SetPluginsEnabled(bool enabled);
void SetPointerLockWillFail();
void SetPointerLockWillRespondAsynchronously();
void SetPopupBlockingEnabled(bool block_popups);
void SetPrinting();
void SetPrintingForFrame(const std::string& frame_name);
void SetPrintingSize(int width, int height);
void SetScriptsAllowed(bool allowed);
void SetShouldGeneratePixelResults(bool);
void SetShouldStayOnPageAfterHandlingBeforeUnload(bool value);
void SetSpellCheckResolvedCallback(v8::Local<v8::Function> callback);
void SetStorageAllowed(bool allowed);
void SetTabKeyCyclesThroughElements(bool tab_key_cycles_through_elements);
void SetTextDirection(const std::string& direction_name);
void SetTextSubpixelPositioning(bool value);
void SetTrustTokenKeyCommitments(const std::string& raw_commitments,
v8::Local<v8::Function> callback);
void SetWillSendRequestClearHeader(const std::string& header);
void SetWillSendRequestClearReferrer();
void SimulateBrowserWindowFocus(bool value);
void NavigateSecondaryWindow(const std::string& url);
void InspectSecondaryWindow();
void SimulateWebNotificationClick(gin::Arguments* args);
void SimulateWebNotificationClose(const std::string& title, bool by_user);
void SimulateWebContentIndexDelete(const std::string& id);
void WaitForPolicyDelegate();
void WaitUntilDone();
void WaitUntilExternalURLLoad();
void DisableAutoResizeMode(int new_width, int new_height);
void EnableAutoResizeMode(int min_width,
int min_height,
int max_width,
int max_height);
void DisableAutomaticDragDrop();
void GoToOffset(int offset);
v8::Local<v8::Value> EvaluateScriptInIsolatedWorldAndReturnValue(
int world_id,
const std::string& script);
bool FindString(const std::string& search_text,
const std::vector<std::string>& options_array);
bool IsCommandEnabled(const std::string& command);
std::string PathToLocalResource(const std::string& path);
std::string PlatformName();
std::string SelectionAsMarkup();
void TextZoomIn();
void TextZoomOut();
void ZoomPageIn();
void ZoomPageOut();
void SetPageZoomFactor(double factor);
std::string TooltipText();
int WebHistoryItemCount();
int WindowCount();
void InvokeV8Callback(v8::UniquePersistent<v8::Function> callback,
std::vector<v8::UniquePersistent<v8::Value>> bound_args,
const std::vector<v8::Local<v8::Value>>& runtime_args);
void OnFrameDestroyed() {
invalid_ = true;
}
TestRunnerBindingsRenderFrameObserver frame_observer_;
bool invalid_ = false;
TestRunner* runner_;
WebFrameTestProxy* const frame_;
SpellCheckClient* const spell_check_;
TestPreferences prefs_;
std::unique_ptr<AppBannerService> app_banner_service_;
base::WeakPtrFactory<TestRunnerBindings> weak_ptr_factory_{this};
};
gin::WrapperInfo TestRunnerBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
void TestRunnerBindings::Install(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check,
bool is_wpt_test,
bool is_main_test_window) {
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
blink::WebLocalFrame* web_frame = frame->GetWebFrame();
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
TestRunnerBindings* wrapped =
new TestRunnerBindings(test_runner, frame, spell_check);
gin::Handle<TestRunnerBindings> bindings =
gin::CreateHandle(isolate, wrapped);
CHECK(!bindings.IsEmpty());
v8::Local<v8::Object> global = context->Global();
v8::Local<v8::Value> v8_bindings = bindings.ToV8();
global->Set(context, gin::StringToV8(isolate, "testRunner"), v8_bindings)
.Check();
if (is_wpt_test && is_main_test_window && !web_frame->Parent() &&
!web_frame->Opener()) {
web_frame->ExecuteScript(blink::WebScriptSource(blink::WebString(
R"(if (!window.testRunner._wpt_reftest_setup) {
window.testRunner._wpt_reftest_setup = true;
window.addEventListener('load', function() {
if (window.assert_equals) // In case of a testharness test.
return;
window.testRunner.waitUntilDone();
const target = document.documentElement;
if (target != null &&
(target.classList.contains('reftest-wait') ||
target.classList.contains('test-wait'))) {
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (!target.classList.contains('reftest-wait') &&
!target.classList.contains('test-wait')) {
window.testRunner.notifyDone();
}
});
});
const config = {attributes: true};
observer.observe(target, config);
var event = new Event('TestRendered', {bubbles: true});
target.dispatchEvent(event);
} else {
document.fonts.ready.then(() => window.testRunner.notifyDone());
}
});
})")));
}
}
TestRunnerBindings::TestRunnerBindings(TestRunner* runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check)
: frame_observer_(this, frame),
runner_(runner),
frame_(frame),
spell_check_(spell_check) {}
TestRunnerBindings::~TestRunnerBindings() = default;
gin::ObjectTemplateBuilder TestRunnerBindings::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<TestRunnerBindings>::GetObjectTemplateBuilder(isolate)
.SetMethod("abortModal", &TestRunnerBindings::NotImplemented)
.SetMethod("addDisallowedURL", &TestRunnerBindings::NotImplemented)
.SetMethod("addOriginAccessAllowListEntry",
&TestRunnerBindings::AddOriginAccessAllowListEntry)
.SetMethod("addWebPageOverlay", &TestRunnerBindings::AddWebPageOverlay)
#if BUILDFLAG(ENABLE_PRINTING)
.SetMethod("capturePrintingPixelsThen",
&TestRunnerBindings::CapturePrintingPixelsThen)
#endif
.SetMethod("checkForLeakedWindows",
&TestRunnerBindings::CheckForLeakedWindows)
.SetMethod("clearAllDatabases", &TestRunnerBindings::ClearAllDatabases)
.SetMethod("clearBackForwardList", &TestRunnerBindings::NotImplemented)
.SetMethod("clearTrustTokenState",
&TestRunnerBindings::ClearTrustTokenState)
.SetMethod("copyImageThen", &TestRunnerBindings::CopyImageThen)
.SetMethod("dropPointerLock", &TestRunnerBindings::DropPointerLock)
.SetMethod("allowPointerLock", &TestRunnerBindings::AllowPointerLock)
.SetMethod("setPointerLockWillFail",
&TestRunnerBindings::SetPointerLockWillFail)
.SetMethod("setPointerLockWillRespondAsynchronously",
&TestRunnerBindings::SetPointerLockWillRespondAsynchronously)
.SetMethod("disableAutoResizeMode",
&TestRunnerBindings::DisableAutoResizeMode)
.SetMethod("disableMockScreenOrientation",
&TestRunnerBindings::DisableMockScreenOrientation)
.SetMethod("setDisallowedSubresourcePathSuffixes",
&TestRunnerBindings::SetDisallowedSubresourcePathSuffixes)
.SetMethod("dispatchBeforeInstallPromptEvent",
&TestRunnerBindings::DispatchBeforeInstallPromptEvent)
.SetMethod("dumpAsMarkup", &TestRunnerBindings::DumpAsMarkup)
.SetMethod("dumpAsText", &TestRunnerBindings::DumpAsText)
.SetMethod("dumpAsTextWithPixelResults",
&TestRunnerBindings::DumpAsTextWithPixelResults)
.SetMethod("dumpAsLayout", &TestRunnerBindings::DumpAsLayout)
.SetMethod("dumpAsLayoutWithPixelResults",
&TestRunnerBindings::DumpAsLayoutWithPixelResults)
.SetMethod("dumpBackForwardList",
&TestRunnerBindings::DumpBackForwardList)
.SetMethod("dumpChildFrames", &TestRunnerBindings::DumpChildFrames)
.SetMethod("dumpDatabaseCallbacks", &TestRunnerBindings::NotImplemented)
.SetMethod("dumpDragImage", &TestRunnerBindings::DumpDragImage)
.SetMethod("dumpEditingCallbacks",
&TestRunnerBindings::DumpEditingCallbacks)
.SetMethod("dumpFrameLoadCallbacks",
&TestRunnerBindings::DumpFrameLoadCallbacks)
.SetMethod("dumpIconChanges", &TestRunnerBindings::DumpIconChanges)
.SetMethod("dumpNavigationPolicy",
&TestRunnerBindings::DumpNavigationPolicy)
.SetMethod("dumpPermissionClientCallbacks",
&TestRunnerBindings::DumpPermissionClientCallbacks)
.SetMethod("dumpPingLoaderCallbacks",
&TestRunnerBindings::DumpPingLoaderCallbacks)
.SetMethod("dumpSelectionRect", &TestRunnerBindings::DumpSelectionRect)
.SetMethod("dumpTitleChanges", &TestRunnerBindings::DumpTitleChanges)
.SetMethod("dumpUserGestureInFrameLoadCallbacks",
&TestRunnerBindings::DumpUserGestureInFrameLoadCallbacks)
.SetMethod("enableAutoResizeMode",
&TestRunnerBindings::EnableAutoResizeMode)
.SetMethod("evaluateScriptInIsolatedWorld",
&TestRunnerBindings::EvaluateScriptInIsolatedWorld)
.SetMethod(
"evaluateScriptInIsolatedWorldAndReturnValue",
&TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue)
.SetMethod("execCommand", &TestRunnerBindings::ExecCommand)
.SetMethod("triggerTestInspectorIssue",
&TestRunnerBindings::TriggerTestInspectorIssue)
.SetMethod("findString", &TestRunnerBindings::FindString)
.SetMethod("focusDevtoolsSecondaryWindow",
&TestRunnerBindings::FocusDevtoolsSecondaryWindow)
.SetMethod("forceNextDrawingBufferCreationToFail",
&TestRunnerBindings::ForceNextDrawingBufferCreationToFail)
.SetMethod("forceNextWebGLContextCreationToFail",
&TestRunnerBindings::ForceNextWebGLContextCreationToFail)
.SetMethod("getBluetoothManualChooserEvents",
&TestRunnerBindings::GetBluetoothManualChooserEvents)
.SetMethod("getManifestThen", &TestRunnerBindings::GetManifestThen)
.SetMethod("getWritableDirectory",
&TestRunnerBindings::GetWritableDirectory)
.SetMethod("insertStyleSheet", &TestRunnerBindings::InsertStyleSheet)
.SetMethod("isCommandEnabled", &TestRunnerBindings::IsCommandEnabled)
.SetMethod("keepWebHistory", &TestRunnerBindings::NotImplemented)
.SetMethod("updateAllLifecyclePhasesAndComposite",
&TestRunnerBindings::UpdateAllLifecyclePhasesAndComposite)
.SetMethod("updateAllLifecyclePhasesAndCompositeThen",
&TestRunnerBindings::UpdateAllLifecyclePhasesAndCompositeThen)
.SetMethod("setAnimationRequiresRaster",
&TestRunnerBindings::SetAnimationRequiresRaster)
.SetMethod("logToStderr", &TestRunnerBindings::LogToStderr)
.SetMethod("notifyDone", &TestRunnerBindings::NotifyDone)
.SetMethod("overridePreference", &TestRunnerBindings::OverridePreference)
.SetMethod("pathToLocalResource",
&TestRunnerBindings::PathToLocalResource)
.SetProperty("platformName", &TestRunnerBindings::PlatformName)
.SetMethod("queueBackNavigation",
&TestRunnerBindings::QueueBackNavigation)
.SetMethod("queueForwardNavigation",
&TestRunnerBindings::QueueForwardNavigation)
.SetMethod("queueLoad", &TestRunnerBindings::QueueLoad)
.SetMethod("queueLoadingScript", &TestRunnerBindings::QueueLoadingScript)
.SetMethod("queueNonLoadingScript",
&TestRunnerBindings::QueueNonLoadingScript)
.SetMethod("queueReload", &TestRunnerBindings::QueueReload)
.SetMethod("removeSpellCheckResolvedCallback",
&TestRunnerBindings::RemoveSpellCheckResolvedCallback)
.SetMethod("removeWebPageOverlay",
&TestRunnerBindings::RemoveWebPageOverlay)
.SetMethod("resolveBeforeInstallPromptPromise",
&TestRunnerBindings::ResolveBeforeInstallPromptPromise)
.SetMethod("selectionAsMarkup", &TestRunnerBindings::SelectionAsMarkup)
.SetMethod("sendBluetoothManualChooserEvent",
&TestRunnerBindings::SendBluetoothManualChooserEvent)
.SetMethod("setAcceptLanguages", &TestRunnerBindings::SetAcceptLanguages)
.SetMethod("setAllowFileAccessFromFileURLs",
&TestRunnerBindings::SetAllowFileAccessFromFileURLs)
.SetMethod("setAllowRunningOfInsecureContent",
&TestRunnerBindings::SetAllowRunningOfInsecureContent)
.SetMethod("setBlockThirdPartyCookies",
&TestRunnerBindings::SetBlockThirdPartyCookies)
.SetMethod("setAudioData", &TestRunnerBindings::SetAudioData)
.SetMethod("setBackingScaleFactor",
&TestRunnerBindings::SetBackingScaleFactor)
.SetMethod("setBluetoothFakeAdapter",
&TestRunnerBindings::SetBluetoothFakeAdapter)
.SetMethod("setBluetoothManualChooser",
&TestRunnerBindings::SetBluetoothManualChooser)
.SetMethod("setBrowserHandlesFocus",
&TestRunnerBindings::SetBrowserHandlesFocus)
.SetMethod("setCallCloseOnWebViews", &TestRunnerBindings::NotImplemented)
.SetMethod("setCaretBrowsingEnabled",
&TestRunnerBindings::SetCaretBrowsingEnabled)
.SetMethod("setColorProfile", &TestRunnerBindings::SetColorProfile)
.SetMethod("setCustomPolicyDelegate",
&TestRunnerBindings::SetCustomPolicyDelegate)
.SetMethod("setCustomTextOutput",
&TestRunnerBindings::SetCustomTextOutput)
.SetMethod("setDatabaseQuota", &TestRunnerBindings::SetDatabaseQuota)
.SetMethod("setDomainRelaxationForbiddenForURLScheme",
&TestRunnerBindings::SetDomainRelaxationForbiddenForURLScheme)
.SetMethod("setDumpConsoleMessages",
&TestRunnerBindings::SetDumpConsoleMessages)
.SetMethod("setDumpJavaScriptDialogs",
&TestRunnerBindings::SetDumpJavaScriptDialogs)
.SetMethod("setEffectiveConnectionType",
&TestRunnerBindings::SetEffectiveConnectionType)
.SetMethod("setFilePathForMockFileDialog",
&TestRunnerBindings::SetFilePathForMockFileDialog)
.SetMethod("setHighlightAds", &TestRunnerBindings::SetHighlightAds)
.SetMethod("setMockSpellCheckerEnabled",
&TestRunnerBindings::SetMockSpellCheckerEnabled)
.SetMethod("setIconDatabaseEnabled", &TestRunnerBindings::NotImplemented)
.SetMethod("setImagesAllowed", &TestRunnerBindings::SetImagesAllowed)
.SetMethod("setIsolatedWorldInfo",
&TestRunnerBindings::SetIsolatedWorldInfo)
.SetMethod("setJavaScriptCanAccessClipboard",
&TestRunnerBindings::SetJavaScriptCanAccessClipboard)
.SetMethod("setMainFrameIsFirstResponder",
&TestRunnerBindings::NotImplemented)
.SetMethod("setMockScreenOrientation",
&TestRunnerBindings::SetMockScreenOrientation)
.SetMethod("setPOSIXLocale", &TestRunnerBindings::SetPOSIXLocale)
.SetMethod("setMainWindowHidden",
&TestRunnerBindings::SetMainWindowHidden)
.SetMethod("setPermission", &TestRunnerBindings::SetPermission)
.SetMethod("setPluginsAllowed", &TestRunnerBindings::SetPluginsAllowed)
.SetMethod("setPluginsEnabled", &TestRunnerBindings::SetPluginsEnabled)
.SetMethod("setPopupBlockingEnabled",
&TestRunnerBindings::SetPopupBlockingEnabled)
.SetMethod("setPrinting", &TestRunnerBindings::SetPrinting)
.SetMethod("setPrintingForFrame",
&TestRunnerBindings::SetPrintingForFrame)
.SetMethod("setPrintingSize", &TestRunnerBindings::SetPrintingSize)
.SetMethod("setScriptsAllowed", &TestRunnerBindings::SetScriptsAllowed)
.SetMethod("setScrollbarPolicy", &TestRunnerBindings::NotImplemented)
.SetMethod("setShouldGeneratePixelResults",
&TestRunnerBindings::SetShouldGeneratePixelResults)
.SetMethod(
"setShouldStayOnPageAfterHandlingBeforeUnload",
&TestRunnerBindings::SetShouldStayOnPageAfterHandlingBeforeUnload)
.SetMethod("setSpellCheckResolvedCallback",
&TestRunnerBindings::SetSpellCheckResolvedCallback)
.SetMethod("setStorageAllowed", &TestRunnerBindings::SetStorageAllowed)
.SetMethod("setTabKeyCyclesThroughElements",
&TestRunnerBindings::SetTabKeyCyclesThroughElements)
.SetMethod("setTextDirection", &TestRunnerBindings::SetTextDirection)
.SetMethod("setTextSubpixelPositioning",
&TestRunnerBindings::SetTextSubpixelPositioning)
.SetMethod("setTrustTokenKeyCommitments",
&TestRunnerBindings::SetTrustTokenKeyCommitments)
.SetMethod("setUseDashboardCompatibilityMode",
&TestRunnerBindings::NotImplemented)
.SetMethod("setWillSendRequestClearHeader",
&TestRunnerBindings::SetWillSendRequestClearHeader)
.SetMethod("setWillSendRequestClearReferrer",
&TestRunnerBindings::SetWillSendRequestClearReferrer)
.SetMethod("setWindowFocus",
&TestRunnerBindings::SimulateBrowserWindowFocus)
.SetMethod("simulateWebNotificationClick",
&TestRunnerBindings::SimulateWebNotificationClick)
.SetMethod("simulateWebNotificationClose",
&TestRunnerBindings::SimulateWebNotificationClose)
.SetMethod("simulateWebContentIndexDelete",
&TestRunnerBindings::SimulateWebContentIndexDelete)
.SetMethod("textZoomIn", &TestRunnerBindings::TextZoomIn)
.SetMethod("textZoomOut", &TestRunnerBindings::TextZoomOut)
.SetMethod("zoomPageIn", &TestRunnerBindings::ZoomPageIn)
.SetMethod("zoomPageOut", &TestRunnerBindings::ZoomPageOut)
.SetMethod("setPageZoomFactor", &TestRunnerBindings::SetPageZoomFactor)
.SetProperty("tooltipText", &TestRunnerBindings::TooltipText)
.SetMethod("waitForPolicyDelegate",
&TestRunnerBindings::WaitForPolicyDelegate)
.SetMethod("waitUntilDone", &TestRunnerBindings::WaitUntilDone)
.SetMethod("waitUntilExternalURLLoad",
&TestRunnerBindings::WaitUntilExternalURLLoad)
.SetProperty("webHistoryItemCount",
&TestRunnerBindings::WebHistoryItemCount)
.SetMethod("windowCount", &TestRunnerBindings::WindowCount)
.SetMethod("disableAutomaticDragDrop",
&TestRunnerBindings::DisableAutomaticDragDrop)
.SetMethod("goToOffset", &TestRunnerBindings::GoToOffset);
}
BoundV8Callback TestRunnerBindings::WrapV8Callback(
v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args_to_bind) {
auto persistent_callback = v8::UniquePersistent<v8::Function>(
blink::MainThreadIsolate(), std::move(v8_callback));
std::vector<v8::UniquePersistent<v8::Value>> persistent_args;
persistent_args.reserve(args_to_bind.size());
for (auto& arg : args_to_bind)
persistent_args.emplace_back(blink::MainThreadIsolate(), std::move(arg));
return base::BindOnce(
&TestRunnerBindings::InvokeV8Callback, weak_ptr_factory_.GetWeakPtr(),
std::move(persistent_callback), std::move(persistent_args));
}
base::OnceClosure TestRunnerBindings::WrapV8Closure(
v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args_to_bind) {
return base::BindOnce(
WrapV8Callback(std::move(v8_callback), std::move(args_to_bind)),
NoV8Args());
}
void TestRunnerBindings::PostV8Callback(
v8::Local<v8::Function> v8_callback,
std::vector<v8::Local<v8::Value>> args) {
if (invalid_)
return;
const auto& task_runner =
GetWebFrame()->GetTaskRunner(blink::TaskType::kInternalTest);
task_runner->PostTask(FROM_HERE,
WrapV8Closure(std::move(v8_callback), std::move(args)));
}
void TestRunnerBindings::InvokeV8Callback(
v8::UniquePersistent<v8::Function> callback,
std::vector<v8::UniquePersistent<v8::Value>> bound_args,
const std::vector<v8::Local<v8::Value>>& runtime_args) {
if (invalid_)
return;
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = GetWebFrame()->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> local_args;
for (auto& arg : bound_args)
local_args.push_back(v8::Local<v8::Value>::New(isolate, std::move(arg)));
for (const auto& arg : runtime_args)
local_args.push_back(arg);
GetWebFrame()->CallFunctionEvenIfScriptDisabled(
v8::Local<v8::Function>::New(isolate, std::move(callback)),
context->Global(), local_args.size(), local_args.data());
}
void TestRunnerBindings::LogToStderr(const std::string& output) {
if (invalid_)
return;
TRACE_EVENT1("shell", "TestRunner::LogToStderr", "output", output);
LOG(ERROR) << output;
}
void TestRunnerBindings::NotifyDone() {
if (invalid_)
return;
runner_->NotifyDone();
}
void TestRunnerBindings::WaitUntilDone() {
if (invalid_)
return;
runner_->WaitUntilDone();
}
void TestRunnerBindings::QueueBackNavigation(int how_far_back) {
if (invalid_)
return;
runner_->QueueBackNavigation(how_far_back);
}
void TestRunnerBindings::QueueForwardNavigation(int how_far_forward) {
if (invalid_)
return;
runner_->QueueForwardNavigation(how_far_forward);
}
void TestRunnerBindings::QueueReload() {
if (invalid_)
return;
runner_->QueueReload();
}
void TestRunnerBindings::QueueLoadingScript(const std::string& script) {
if (invalid_)
return;
runner_->QueueLoadingScript(script);
}
void TestRunnerBindings::QueueNonLoadingScript(const std::string& script) {
if (invalid_)
return;
runner_->QueueNonLoadingScript(script);
}
void TestRunnerBindings::QueueLoad(gin::Arguments* args) {
if (invalid_)
return;
std::string url;
std::string target;
args->GetNext(&url);
args->GetNext(&target);
runner_->QueueLoad(GURL(GetWebFrame()->GetDocument().Url()), url, target);
}
void TestRunnerBindings::SetCustomPolicyDelegate(gin::Arguments* args) {
if (invalid_)
return;
runner_->SetCustomPolicyDelegate(args);
}
void TestRunnerBindings::WaitForPolicyDelegate() {
if (invalid_)
return;
runner_->WaitForPolicyDelegate();
}
int TestRunnerBindings::WindowCount() {
if (invalid_)
return 0;
return runner_->InProcessWindowCount();
}
void TestRunnerBindings::SetTabKeyCyclesThroughElements(
bool tab_key_cycles_through_elements) {
if (invalid_)
return;
blink::WebView* web_view = GetWebFrame()->View();
web_view->SetTabKeyCyclesThroughElements(tab_key_cycles_through_elements);
}
void TestRunnerBindings::ExecCommand(gin::Arguments* args) {
if (invalid_)
return;
std::string command;
args->GetNext(&command);
std::string value;
if (args->Length() >= 3) {
args->Skip();
args->GetNext(&value);
}
GetWebFrame()->ExecuteCommand(blink::WebString::FromUTF8(command),
blink::WebString::FromUTF8(value));
}
void TestRunnerBindings::TriggerTestInspectorIssue(gin::Arguments* args) {
if (invalid_)
return;
GetWebFrame()->AddInspectorIssue(
blink::mojom::InspectorIssueCode::kCookieIssue);
}
bool TestRunnerBindings::IsCommandEnabled(const std::string& command) {
if (invalid_)
return false;
return GetWebFrame()->IsCommandEnabled(blink::WebString::FromUTF8(command));
}
void TestRunnerBindings::SetDomainRelaxationForbiddenForURLScheme(
bool forbidden,
const std::string& scheme) {
if (invalid_)
return;
blink::SetDomainRelaxationForbiddenForTest(
forbidden, blink::WebString::FromUTF8(scheme));
}
void TestRunnerBindings::SetDumpConsoleMessages(bool enabled) {
if (invalid_)
return;
runner_->SetDumpConsoleMessages(enabled);
}
void TestRunnerBindings::SetDumpJavaScriptDialogs(bool enabled) {
if (invalid_)
return;
runner_->SetDumpJavaScriptDialogs(enabled);
}
void TestRunnerBindings::SetEffectiveConnectionType(
const std::string& connection_type) {
if (invalid_)
return;
blink::WebEffectiveConnectionType web_type =
blink::WebEffectiveConnectionType::kTypeUnknown;
if (connection_type == "TypeUnknown")
web_type = blink::WebEffectiveConnectionType::kTypeUnknown;
else if (connection_type == "TypeOffline")
web_type = blink::WebEffectiveConnectionType::kTypeOffline;
else if (connection_type == "TypeSlow2G")
web_type = blink::WebEffectiveConnectionType::kTypeSlow2G;
else if (connection_type == "Type2G")
web_type = blink::WebEffectiveConnectionType::kType2G;
else if (connection_type == "Type3G")
web_type = blink::WebEffectiveConnectionType::kType3G;
else if (connection_type == "Type4G")
web_type = blink::WebEffectiveConnectionType::kType4G;
else
NOTREACHED();
if (runner_)
runner_->SetEffectiveConnectionType(web_type);
}
std::string TestRunnerBindings::GetWritableDirectory() {
if (invalid_)
return {};
base::FilePath result;
runner_->GetWebTestControlHostRemote()->GetWritableDirectory(&result);
return result.AsUTF8Unsafe();
}
void TestRunnerBindings::SetFilePathForMockFileDialog(const std::string& path) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetFilePathForMockFileDialog(
base::FilePath::FromUTF8Unsafe(path));
}
void TestRunnerBindings::SetMockSpellCheckerEnabled(bool enabled) {
if (invalid_)
return;
spell_check_->SetEnabled(enabled);
}
void TestRunnerBindings::SetSpellCheckResolvedCallback(
v8::Local<v8::Function> callback) {
if (invalid_)
return;
spell_check_->SetSpellCheckResolvedCallback(callback);
}
void TestRunnerBindings::RemoveSpellCheckResolvedCallback() {
if (invalid_)
return;
spell_check_->RemoveSpellCheckResolvedCallback();
}
v8::Local<v8::Value>
TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue(
int world_id,
const std::string& script) {
if (invalid_ || world_id <= 0 || world_id >= (1 << 29))
return {};
blink::WebScriptSource source(blink::WebString::FromUTF8(script));
return GetWebFrame()->ExecuteScriptInIsolatedWorldAndReturnValue(
world_id, source, blink::BackForwardCacheAware::kAllow);
}
void TestRunnerBindings::EvaluateScriptInIsolatedWorld(
int world_id,
const std::string& script) {
if (invalid_ || world_id <= 0 || world_id >= (1 << 29))
return;
blink::WebScriptSource source(blink::WebString::FromUTF8(script));
GetWebFrame()->ExecuteScriptInIsolatedWorld(
world_id, source, blink::BackForwardCacheAware::kAllow);
}
void TestRunnerBindings::SetIsolatedWorldInfo(
int world_id,
v8::Local<v8::Value> security_origin,
v8::Local<v8::Value> content_security_policy) {
if (invalid_)
return;
if (world_id <= content::ISOLATED_WORLD_ID_GLOBAL ||
blink::IsEqualOrExceedEmbedderWorldIdLimit(world_id))
return;
if (!security_origin->IsString() && !security_origin->IsNull())
return;
if (!content_security_policy->IsString() &&
!content_security_policy->IsNull()) {
return;
}
if (content_security_policy->IsString() && security_origin->IsNull())
return;
blink::WebIsolatedWorldInfo info;
if (security_origin->IsString()) {
info.security_origin = blink::WebSecurityOrigin::CreateFromString(
web_test_string_util::V8StringToWebString(
blink::MainThreadIsolate(), security_origin.As<v8::String>()));
}
if (content_security_policy->IsString()) {
info.content_security_policy = web_test_string_util::V8StringToWebString(
blink::MainThreadIsolate(), content_security_policy.As<v8::String>());
}
GetWebFrame()->ClearIsolatedWorldCSPForTesting(world_id);
blink::SetIsolatedWorldInfo(world_id, info);
}
void TestRunnerBindings::AddOriginAccessAllowListEntry(
const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains) {
if (invalid_)
return;
GURL url(source_origin);
DCHECK(url.is_valid());
DCHECK(url.has_scheme());
DCHECK(url.has_host());
runner_->AddOriginAccessAllowListEntry(source_origin, destination_protocol,
destination_host,
allow_destination_subdomains);
}
void TestRunnerBindings::InsertStyleSheet(const std::string& source_code) {
if (invalid_)
return;
GetWebFrame()->GetDocument().InsertStyleSheet(
blink::WebString::FromUTF8(source_code));
}
bool TestRunnerBindings::FindString(
const std::string& search_text,
const std::vector<std::string>& options_array) {
if (invalid_)
return false;
bool match_case = true;
bool forward = true;
bool new_session = false;
bool wrap_around = false;
bool async = false;
for (const auto& option : options_array) {
if (option == "CaseInsensitive")
match_case = false;
else if (option == "Backwards")
forward = false;
else if (option == "StartInSelection")
new_session = true;
else if (option == "WrapAround")
wrap_around = true;
else if (option == "Async")
async = true;
}
const bool find_result = GetWebFrame()->FindForTesting(
0, blink::WebString::FromUTF8(search_text), match_case, forward,
new_session, false , wrap_around, async);
return find_result;
}
std::string TestRunnerBindings::SelectionAsMarkup() {
if (invalid_)
return {};
return GetWebFrame()->SelectionAsMarkup().Utf8();
}
void TestRunnerBindings::SetTextSubpixelPositioning(bool value) {
if (invalid_)
return;
runner_->SetTextSubpixelPositioning(value);
}
void TestRunnerBindings::SetTrustTokenKeyCommitments(
const std::string& raw_commitments,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetTrustTokenKeyCommitments(
raw_commitments, WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetMainWindowHidden(bool hidden) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetMainWindowHidden(hidden);
}
void TestRunnerBindings::SetTextDirection(const std::string& direction_name) {
if (invalid_)
return;
base::i18n::TextDirection direction;
if (direction_name == "auto")
direction = base::i18n::TextDirection::UNKNOWN_DIRECTION;
else if (direction_name == "rtl")
direction = base::i18n::TextDirection::RIGHT_TO_LEFT;
else if (direction_name == "ltr")
direction = base::i18n::TextDirection::LEFT_TO_RIGHT;
else
return;
GetWebFrame()->SetTextDirectionForTesting(direction);
}
void TestRunnerBindings::EnableAutoResizeMode(int min_width,
int min_height,
int max_width,
int max_height) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
if (max_width <= 0 || max_height <= 0)
return;
gfx::Size min_size(min_width, min_height);
gfx::Size max_size(max_width, max_height);
runner_->GetWebTestControlHostRemote()->EnableAutoResize(min_size, max_size);
}
void TestRunnerBindings::DisableAutoResizeMode(int new_width, int new_height) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
if (new_width <= 0 || new_height <= 0)
return;
gfx::Size new_size(new_width, new_height);
runner_->GetWebTestControlHostRemote()->DisableAutoResize(new_size);
}
void TestRunnerBindings::SetMockScreenOrientation(
const std::string& orientation) {
if (invalid_)
return;
runner_->SetMockScreenOrientation(GetWebFrame()->View(), orientation);
}
void TestRunnerBindings::DisableMockScreenOrientation() {
if (invalid_)
return;
runner_->DisableMockScreenOrientation(GetWebFrame()->View());
}
void TestRunnerBindings::SetDisallowedSubresourcePathSuffixes(
std::vector<std::string> suffixes,
bool block_subresources) {
if (invalid_)
return;
GetWebFrame()->GetDocumentLoader()->SetSubresourceFilter(
new FakeSubresourceFilter(std::move(suffixes), block_subresources));
}
void TestRunnerBindings::SetPopupBlockingEnabled(bool block_popups) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetPopupBlockingEnabled(block_popups);
}
void TestRunnerBindings::SetJavaScriptCanAccessClipboard(bool can_access) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
prefs_.java_script_can_access_clipboard = can_access;
runner_->OnTestPreferencesChanged(prefs_, frame_);
}
void TestRunnerBindings::SetAllowFileAccessFromFileURLs(bool allow) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
prefs_.allow_file_access_from_file_urls = allow;
runner_->OnTestPreferencesChanged(prefs_, frame_);
}
void TestRunnerBindings::OverridePreference(gin::Arguments* args) {
if (invalid_)
return;
if (args->Length() != 2) {
args->ThrowTypeError("overridePreference expects 2 arguments");
return;
}
std::string key;
if (!args->GetNext(&key)) {
args->ThrowError();
return;
}
if (key == "WebKitDefaultFontSize") {
ConvertAndSet(args, &prefs_.default_font_size);
} else if (key == "WebKitMinimumFontSize") {
ConvertAndSet(args, &prefs_.minimum_font_size);
} else if (key == "WebKitDefaultTextEncodingName") {
ConvertAndSet(args, &prefs_.default_text_encoding_name);
} else if (key == "WebKitJavaScriptEnabled") {
ConvertAndSet(args, &prefs_.java_script_enabled);
} else if (key == "WebKitSupportsMultipleWindows") {
ConvertAndSet(args, &prefs_.supports_multiple_windows);
} else if (key == "WebKitDisplayImagesKey") {
ConvertAndSet(args, &prefs_.loads_images_automatically);
} else if (key == "WebKitPluginsEnabled") {
ConvertAndSet(args, &prefs_.plugins_enabled);
} else if (key == "WebKitTabToLinksPreferenceKey") {
ConvertAndSet(args, &prefs_.tabs_to_links);
} else if (key == "WebKitCSSGridLayoutEnabled") {
ConvertAndSet(args, &prefs_.experimental_css_grid_layout_enabled);
} else if (key == "WebKitHyperlinkAuditingEnabled") {
ConvertAndSet(args, &prefs_.hyperlink_auditing_enabled);
} else if (key == "WebKitEnableCaretBrowsing") {
ConvertAndSet(args, &prefs_.caret_browsing_enabled);
} else if (key == "WebKitAllowRunningInsecureContent") {
ConvertAndSet(args, &prefs_.allow_running_of_insecure_content);
} else if (key == "WebKitDisableReadingFromCanvas") {
ConvertAndSet(args, &prefs_.disable_reading_from_canvas);
} else if (key == "WebKitStrictMixedContentChecking") {
ConvertAndSet(args, &prefs_.strict_mixed_content_checking);
} else if (key == "WebKitStrictPowerfulFeatureRestrictions") {
ConvertAndSet(args, &prefs_.strict_powerful_feature_restrictions);
} else if (key == "WebKitWebSecurityEnabled") {
ConvertAndSet(args, &prefs_.web_security_enabled);
} else if (key == "WebKitSpatialNavigationEnabled") {
ConvertAndSet(args, &prefs_.spatial_navigation_enabled);
} else {
args->ThrowTypeError("Invalid name for preference: " + key);
}
runner_->OnTestPreferencesChanged(prefs_, frame_);
}
void TestRunnerBindings::SetAcceptLanguages(
const std::string& accept_languages) {
if (invalid_)
return;
runner_->SetAcceptLanguages(accept_languages);
}
void TestRunnerBindings::SetPluginsEnabled(bool enabled) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
prefs_.plugins_enabled = enabled;
runner_->OnTestPreferencesChanged(prefs_, frame_);
}
void TestRunnerBindings::DumpEditingCallbacks() {
if (invalid_)
return;
runner_->DumpEditingCallbacks();
}
void TestRunnerBindings::DumpAsMarkup() {
if (invalid_)
return;
runner_->DumpAsMarkup();
}
void TestRunnerBindings::DumpAsText() {
if (invalid_)
return;
runner_->DumpAsText();
}
void TestRunnerBindings::DumpAsTextWithPixelResults() {
if (invalid_)
return;
runner_->DumpAsTextWithPixelResults();
}
void TestRunnerBindings::DumpAsLayout() {
if (invalid_)
return;
runner_->DumpAsLayout();
}
void TestRunnerBindings::DumpAsLayoutWithPixelResults() {
if (invalid_)
return;
runner_->DumpAsLayoutWithPixelResults();
}
void TestRunnerBindings::DumpChildFrames() {
if (invalid_)
return;
runner_->DumpChildFrames();
}
void TestRunnerBindings::DumpIconChanges() {
if (invalid_)
return;
runner_->DumpIconChanges();
}
void TestRunnerBindings::SetAudioData(const gin::ArrayBufferView& view) {
if (invalid_)
return;
runner_->SetAudioData(view);
}
void TestRunnerBindings::DumpFrameLoadCallbacks() {
if (invalid_)
return;
runner_->DumpFrameLoadCallbacks();
}
void TestRunnerBindings::DumpPingLoaderCallbacks() {
if (invalid_)
return;
runner_->DumpPingLoaderCallbacks();
}
void TestRunnerBindings::DumpUserGestureInFrameLoadCallbacks() {
if (invalid_)
return;
runner_->DumpUserGestureInFrameLoadCallbacks();
}
void TestRunnerBindings::DumpTitleChanges() {
if (invalid_)
return;
runner_->DumpTitleChanges();
}
void TestRunnerBindings::SetCaretBrowsingEnabled() {
if (invalid_)
return;
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetCaretBrowsingEnabled(true);
}
void TestRunnerBindings::SetImagesAllowed(bool allowed) {
if (invalid_)
return;
runner_->SetImagesAllowed(allowed);
}
void TestRunnerBindings::SetScriptsAllowed(bool allowed) {
if (invalid_)
return;
runner_->SetScriptsAllowed(allowed);
}
void TestRunnerBindings::SetStorageAllowed(bool allowed) {
if (invalid_)
return;
runner_->SetStorageAllowed(allowed);
}
void TestRunnerBindings::SetPluginsAllowed(bool allowed) {
if (invalid_)
return;
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetPluginsEnabled(allowed);
}
void TestRunnerBindings::SetAllowRunningOfInsecureContent(bool allowed) {
if (invalid_)
return;
runner_->SetAllowRunningOfInsecureContent(allowed);
}
void TestRunnerBindings::DumpPermissionClientCallbacks() {
if (invalid_)
return;
runner_->DumpPermissionClientCallbacks();
}
void TestRunnerBindings::DumpBackForwardList() {
if (invalid_)
return;
runner_->DumpBackForwardList();
}
void TestRunnerBindings::DumpSelectionRect() {
if (invalid_)
return;
runner_->DumpSelectionRect();
}
void TestRunnerBindings::SetPrinting() {
if (invalid_)
return;
runner_->SetPrinting();
}
void TestRunnerBindings::SetPrintingForFrame(const std::string& frame_name) {
if (invalid_)
return;
runner_->SetPrintingForFrame(frame_name);
}
void TestRunnerBindings::SetPrintingSize(int width, int height) {
if (invalid_)
return;
runner_->SetPrintingSize(width, height);
}
void TestRunnerBindings::ClearTrustTokenState(
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->ClearTrustTokenState(
WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetShouldGeneratePixelResults(bool value) {
if (invalid_)
return;
runner_->SetShouldGeneratePixelResults(value);
}
void TestRunnerBindings::SetShouldStayOnPageAfterHandlingBeforeUnload(
bool value) {
if (invalid_)
return;
runner_->SetShouldStayOnPageAfterHandlingBeforeUnload(value);
}
void TestRunnerBindings::SetWillSendRequestClearHeader(
const std::string& header) {
if (invalid_)
return;
runner_->SetWillSendRequestClearHeader(header);
}
void TestRunnerBindings::SetWillSendRequestClearReferrer() {
if (invalid_)
return;
runner_->SetWillSendRequestClearReferrer();
}
void TestRunnerBindings::WaitUntilExternalURLLoad() {
if (invalid_)
return;
runner_->WaitUntilExternalURLLoad();
}
void TestRunnerBindings::DumpDragImage() {
if (invalid_)
return;
runner_->DumpDragImage();
}
void TestRunnerBindings::DumpNavigationPolicy() {
if (invalid_)
return;
runner_->DumpNavigationPolicy();
}
void TestRunnerBindings::ClearAllDatabases() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->ClearAllDatabases();
}
void TestRunnerBindings::SetDatabaseQuota(int quota) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetDatabaseQuota(quota);
}
void TestRunnerBindings::SetBlockThirdPartyCookies(bool block) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->BlockThirdPartyCookies(block);
}
void TestRunnerBindings::SimulateBrowserWindowFocus(bool value) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
runner_->FocusWindow(frame_, value);
}
std::string TestRunnerBindings::PathToLocalResource(const std::string& path) {
if (invalid_)
return {};
return RewriteFileURLToLocalResource(path).GetString().Utf8();
}
void TestRunnerBindings::SetBackingScaleFactor(
double value,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
double limited_value = fmin(15, value);
frame_->GetLocalRootWebFrameWidget()->SetDeviceScaleFactorForTesting(
limited_value);
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
WrapV8Closure(std::move(v8_callback)).Run();
}
void TestRunnerBindings::SetColorProfile(const std::string& name,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
gfx::ColorSpace color_space;
if (name == "genericRGB") {
color_space = gfx::ICCProfileForTestingGenericRGB().GetColorSpace();
} else if (name == "sRGB") {
color_space = gfx::ColorSpace::CreateSRGB();
} else if (name == "colorSpin") {
color_space = gfx::ICCProfileForTestingColorSpin().GetColorSpace();
} else if (name == "adobeRGB") {
color_space = gfx::ICCProfileForTestingAdobeRGB().GetColorSpace();
}
GetWebFrame()->View()->SetDeviceColorSpaceForTesting(color_space);
WrapV8Closure(std::move(v8_callback)).Run();
}
void TestRunnerBindings::SetBluetoothFakeAdapter(
const std::string& adapter_name,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
runner_->GetBluetoothFakeAdapterSetter().Set(
adapter_name, WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetBluetoothManualChooser(bool enable) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetBluetoothManualChooser(enable);
}
static void GetBluetoothManualChooserEventsReply(
base::WeakPtr<TestRunnerBindings> test_runner,
blink::WebLocalFrame* frame,
BoundV8Callback callback,
const std::vector<std::string>& events) {
if (!test_runner)
return;
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
v8::Local<v8::Value> arg;
bool converted = gin::TryConvertToV8(isolate, events, &arg);
CHECK(converted);
std::move(callback).Run({
arg,
});
}
void TestRunnerBindings::GetBluetoothManualChooserEvents(
v8::Local<v8::Function> callback) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->GetBluetoothManualChooserEvents(
base::BindOnce(&GetBluetoothManualChooserEventsReply,
weak_ptr_factory_.GetWeakPtr(), GetWebFrame(),
WrapV8Callback(std::move(callback))));
}
void TestRunnerBindings::SetBrowserHandlesFocus(bool enable) {
if (invalid_)
return;
blink::SetBrowserCanHandleFocusForWebTest(enable);
}
void TestRunnerBindings::SendBluetoothManualChooserEvent(
const std::string& event,
const std::string& argument) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SendBluetoothManualChooserEvent(
event, argument);
}
void TestRunnerBindings::SetPOSIXLocale(const std::string& locale) {
if (invalid_)
return;
setlocale(LC_ALL, locale.c_str());
setlocale(LC_NUMERIC, "C");
}
void TestRunnerBindings::SimulateWebNotificationClick(gin::Arguments* args) {
if (invalid_)
return;
DCHECK_GE(args->Length(), 1);
std::string title;
int action_index = std::numeric_limits<int32_t>::min();
absl::optional<std::u16string> reply;
if (!args->GetNext(&title)) {
args->ThrowError();
return;
}
if (args->Length() >= 2) {
if (!args->GetNext(&action_index)) {
args->ThrowError();
return;
}
}
if (args->Length() >= 3) {
std::string reply_string;
if (!args->GetNext(&reply_string)) {
args->ThrowError();
return;
}
reply = base::UTF8ToUTF16(reply_string);
}
runner_->GetWebTestControlHostRemote()->SimulateWebNotificationClick(
title, action_index, reply);
}
void TestRunnerBindings::SimulateWebNotificationClose(const std::string& title,
bool by_user) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SimulateWebNotificationClose(title,
by_user);
}
void TestRunnerBindings::SimulateWebContentIndexDelete(const std::string& id) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SimulateWebContentIndexDelete(id);
}
void TestRunnerBindings::SetHighlightAds() {
if (invalid_)
return;
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetHighlightAds(true);
}
void TestRunnerBindings::AddWebPageOverlay() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
frame_->GetLocalRootWebFrameWidget()->SetMainFrameOverlayColor(SK_ColorCYAN);
}
void TestRunnerBindings::RemoveWebPageOverlay() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
frame_->GetLocalRootWebFrameWidget()->SetMainFrameOverlayColor(
SK_ColorTRANSPARENT);
}
void TestRunnerBindings::UpdateAllLifecyclePhasesAndComposite() {
if (invalid_)
return;
frame_->GetLocalRootFrameWidgetTestHelper()
->UpdateAllLifecyclePhasesAndComposite(base::DoNothing());
}
void TestRunnerBindings::UpdateAllLifecyclePhasesAndCompositeThen(
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
frame_->GetLocalRootFrameWidgetTestHelper()
->UpdateAllLifecyclePhasesAndComposite(
WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetAnimationRequiresRaster(bool do_raster) {
if (invalid_)
return;
runner_->SetAnimationRequiresRaster(do_raster);
}
static void GetManifestReply(BoundV8Callback callback,
const blink::WebURL& manifest_url) {
std::move(callback).Run(NoV8Args());
}
void TestRunnerBindings::GetManifestThen(v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
blink::WebManifestManager::RequestManifestForTesting(
GetWebFrame(),
base::BindOnce(GetManifestReply, WrapV8Callback(std::move(v8_callback))));
}
#if BUILDFLAG(ENABLE_PRINTING)
void TestRunnerBindings::CapturePrintingPixelsThen(
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
blink::WebLocalFrame* frame = GetWebFrame();
SkBitmap bitmap =
PrintFrameToBitmap(frame, runner_->GetPrintingPageSize(frame),
runner_->GetPrintingPageRanges(frame));
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = GetWebFrame()->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
WrapV8Callback(std::move(v8_callback))
.Run({
ConvertBitmapToV8(context_scope, bitmap),
});
}
#endif
void TestRunnerBindings::CheckForLeakedWindows() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->CheckForLeakedWindows();
}
void TestRunnerBindings::CopyImageThen(int x,
int y,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
mojo::Remote<blink::mojom::ClipboardHost> remote_clipboard;
frame_->GetBrowserInterfaceBroker()->GetInterface(
remote_clipboard.BindNewPipeAndPassReceiver());
blink::ClipboardSequenceNumberToken sequence_number_before;
CHECK(remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
&sequence_number_before));
GetWebFrame()->CopyImageAtForTesting(gfx::Point(x, y));
auto sequence_number_after = sequence_number_before;
while (sequence_number_before.value() == sequence_number_after.value()) {
remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
&sequence_number_after);
}
mojo_base::BigBuffer png_data;
remote_clipboard->ReadPng(ui::ClipboardBuffer::kCopyPaste, &png_data);
SkBitmap bitmap;
gfx::PNGCodec::Decode(png_data.data(), png_data.size(), &bitmap);
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = GetWebFrame()->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
WrapV8Callback(std::move(v8_callback))
.Run(ConvertBitmapToV8(context_scope, std::move(bitmap)));
}
void TestRunnerBindings::DropPointerLock() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->DropPointerLock();
}
void TestRunnerBindings::SetPointerLockWillFail() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetPointerLockWillFail();
}
void TestRunnerBindings::SetPointerLockWillRespondAsynchronously() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()
->SetPointerLockWillRespondAsynchronously();
}
void TestRunnerBindings::AllowPointerLock() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->AllowPointerLock();
}
void TestRunnerBindings::SetCustomTextOutput(const std::string& output) {
if (invalid_)
return;
runner_->SetCustomTextOutput(output);
}
void TestRunnerBindings::SetPermission(const std::string& name,
const std::string& value,
const std::string& origin,
const std::string& embedding_origin) {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->SetPermission(
name, blink::ToPermissionStatus(value), GURL(origin),
GURL(embedding_origin));
}
static void DispatchBeforeInstallPromptEventReply(BoundV8Callback callback,
bool cancelled) {
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
std::move(callback).Run({
v8::Boolean::New(isolate, cancelled),
});
}
void TestRunnerBindings::DispatchBeforeInstallPromptEvent(
const std::vector<std::string>& event_platforms,
v8::Local<v8::Function> v8_callback) {
if (invalid_)
return;
app_banner_service_ = std::make_unique<AppBannerService>();
frame_->BindLocalInterface(blink::mojom::AppBannerController::Name_,
app_banner_service_->controller()
.BindNewPipeAndPassReceiver()
.PassPipe());
app_banner_service_->SendBannerPromptRequest(
event_platforms, base::BindOnce(&DispatchBeforeInstallPromptEventReply,
WrapV8Callback(std::move(v8_callback))));
}
void TestRunnerBindings::ResolveBeforeInstallPromptPromise(
const std::string& platform) {
if (invalid_)
return;
if (app_banner_service_) {
app_banner_service_->ResolvePromise(platform);
app_banner_service_.reset();
}
}
std::string TestRunnerBindings::PlatformName() {
if (invalid_)
return {};
return runner_->platform_name_;
}
void TestRunnerBindings::TextZoomIn() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
blink::WebFrameWidget* widget = frame_->GetLocalRootWebFrameWidget();
widget->SetTextZoomFactor(widget->TextZoomFactor() * 1.2f);
}
void TestRunnerBindings::TextZoomOut() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
blink::WebFrameWidget* widget = frame_->GetLocalRootWebFrameWidget();
widget->SetTextZoomFactor(widget->TextZoomFactor() / 1.2f);
}
void TestRunnerBindings::ZoomPageIn() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
blink::WebView* web_view = GetWebFrame()->View();
frame_->GetLocalRootWebFrameWidget()->SetZoomLevelForTesting(
web_view->ZoomLevel() + 1);
}
void TestRunnerBindings::ZoomPageOut() {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
blink::WebView* web_view = GetWebFrame()->View();
frame_->GetLocalRootWebFrameWidget()->SetZoomLevelForTesting(
web_view->ZoomLevel() - 1);
}
void TestRunnerBindings::SetPageZoomFactor(double zoom_factor) {
if (invalid_)
return;
if (!frame_->IsMainFrame())
return;
frame_->GetLocalRootWebFrameWidget()->SetZoomLevelForTesting(
blink::PageZoomFactorToZoomLevel(zoom_factor));
}
std::string TestRunnerBindings::TooltipText() {
if (invalid_)
return {};
blink::WebString tooltip_text =
frame_->GetLocalRootWebFrameWidget()->GetLastToolTipTextForTesting();
return tooltip_text.Utf8();
}
int TestRunnerBindings::WebHistoryItemCount() {
if (invalid_)
return 0;
return frame_->GetWebFrame()->View()->HistoryBackListCount() +
frame_->GetWebFrame()->View()->HistoryForwardListCount() + 1;
}
void TestRunnerBindings::ForceNextWebGLContextCreationToFail() {
if (invalid_)
return;
blink::ForceNextWebGLContextCreationToFailForTest();
}
void TestRunnerBindings::FocusDevtoolsSecondaryWindow() {
if (invalid_)
return;
runner_->GetWebTestControlHostRemote()->FocusDevtoolsSecondaryWindow();
}
void TestRunnerBindings::ForceNextDrawingBufferCreationToFail() {
if (invalid_)
return;
blink::ForceNextDrawingBufferCreationToFailForTest();
}
void TestRunnerBindings::DisableAutomaticDragDrop() {
if (invalid_) {
return;
}
runner_->DisableAutomaticDragDrop();
}
void TestRunnerBindings::GoToOffset(int offset) {
if (invalid_) {
return;
}
runner_->GoToOffset(offset);
}
void TestRunnerBindings::NotImplemented(const gin::Arguments& args) {}
class TestRunner::MainWindowTracker : public blink::WebViewObserver {
public:
MainWindowTracker(blink::WebView* view, TestRunner* test_runner)
: blink::WebViewObserver(view), test_runner_(test_runner) {}
void OnDestruct() override {
EraseIf(test_runner_->main_windows_, base::MatchesUniquePtr(this));
}
private:
TestRunner* const test_runner_;
};
TestRunner::WorkQueue::WorkQueue(TestRunner* controller)
: controller_(controller) {}
void TestRunner::WorkQueue::Reset() {
set_frozen(false);
set_has_items(false);
states_.ResetChangeTracking();
set_loading(true);
}
void TestRunner::WorkQueue::AddWork(mojom::WorkItemPtr work_item) {
if (is_frozen())
return;
controller_->GetWebTestControlHostRemote()->WorkItemAdded(
std::move(work_item));
set_has_items(true);
OnStatesChanged();
}
void TestRunner::WorkQueue::RequestWork() {
controller_->GetWebTestControlHostRemote()->RequestWorkItem();
}
void TestRunner::WorkQueue::ProcessWorkItem(mojom::WorkItemPtr work_item) {
set_loading(true);
bool started_load = ProcessWorkItemInternal(std::move(work_item));
if (started_load) {
if (loading_)
controller_->frame_will_start_load_ = true;
return;
}
RequestWork();
}
bool TestRunner::WorkQueue::ProcessWorkItemInternal(
mojom::WorkItemPtr work_item) {
switch (work_item->which()) {
case mojom::WorkItem::Tag::kBackForward: {
mojom::WorkItemBackForwardPtr& item_back_forward =
work_item->get_back_forward();
controller_->GoToOffset(item_back_forward->distance);
return true;
}
case mojom::WorkItem::Tag::kLoadingScript: {
mojom::WorkItemLoadingScriptPtr& item_loading_script =
work_item->get_loading_script();
WebFrameTestProxy* main_frame =
controller_->FindInProcessMainWindowMainFrame();
DCHECK(main_frame);
main_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource(
blink::WebString::FromUTF8(item_loading_script->script)));
return true;
}
case mojom::WorkItem::Tag::kNonLoadingScript: {
mojom::WorkItemNonLoadingScriptPtr& item_non_loading_script =
work_item->get_non_loading_script();
WebFrameTestProxy* main_frame =
controller_->FindInProcessMainWindowMainFrame();
DCHECK(main_frame);
main_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource(
blink::WebString::FromUTF8(item_non_loading_script->script)));
return false;
}
case mojom::WorkItem::Tag::kLoad: {
mojom::WorkItemLoadPtr& item_load = work_item->get_load();
controller_->LoadURLForFrame(GURL(item_load->url), item_load->target);
return true;
}
case mojom::WorkItem::Tag::kReload:
controller_->Reload();
return true;
}
NOTREACHED();
return false;
}
void TestRunner::WorkQueue::ReplicateStates(const base::Value::Dict& values) {
states_.ApplyUntrackedChanges(values);
if (!has_items())
controller_->FinishTestIfReady();
}
void TestRunner::WorkQueue::OnStatesChanged() {
if (states_.changed_values().empty())
return;
controller_->GetWebTestControlHostRemote()->WorkQueueStatesChanged(
states_.changed_values().Clone());
states_.ResetChangeTracking();
}
TestRunner::TestRunner()
: work_queue_(this),
test_content_settings_client_(this, &web_test_runtime_flags_) {
blink::WebTestingSupport::SaveRuntimeFeatures();
Reset();
}
TestRunner::~TestRunner() = default;
void TestRunner::Install(WebFrameTestProxy* frame,
SpellCheckClient* spell_check) {
bool is_main_test_window = IsFrameInMainWindow(frame->GetWebFrame());
TestRunnerBindings::Install(this, frame, spell_check,
IsWebPlatformTestsMode(), is_main_test_window);
fake_screen_orientation_impl_.OverrideAssociatedInterfaceProviderForFrame(
frame->GetWebFrame());
gamepad_controller_.Install(frame);
frame->GetWebFrame()->View()->SetScreenOrientationOverrideForTesting(
fake_screen_orientation_impl_.CurrentOrientationType());
}
void TestRunner::Reset() {
loading_frames_.clear();
web_test_runtime_flags_.Reset();
fake_screen_orientation_impl_.ResetData();
gamepad_controller_.Reset();
drag_image_.reset();
blink::WebTestingSupport::ResetRuntimeFeatures();
blink::WebCache::Clear();
blink::WebSecurityPolicy::ClearOriginAccessList();
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
blink::WebFontRenderStyle::SetSubpixelPositioning(false);
#endif
blink::ResetDomainRelaxationForTest();
blink::SetBrowserCanHandleFocusForWebTest(false);
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
dump_as_audio_ = false;
dump_back_forward_list_ = false;
test_repaint_ = false;
sweep_horizontally_ = false;
animation_requires_raster_ = false;
main_frame_loaded_ = false;
frame_will_start_load_ = false;
did_notify_done_ = false;
http_headers_to_clear_.clear();
clear_referrer_ = false;
platform_name_ = "chromium";
weak_factory_.InvalidateWeakPtrs();
work_queue_.Reset();
}
void TestRunner::ResetWebView(blink::WebView* web_view) {
web_view->SetTabKeyCyclesThroughElements(true);
web_view->GetSettings()->SetHighlightAds(false);
web_view->GetSettings()->SetCaretBrowsingEnabled(false);
web_view->DisableAutoResizeForTesting(gfx::Size());
web_view->SetScreenOrientationOverrideForTesting(
fake_screen_orientation_impl_.CurrentOrientationType());
}
void TestRunner::ResetWebFrameWidget(blink::WebFrameWidget* web_frame_widget) {
web_frame_widget->SetDeviceScaleFactorForTesting(0);
web_frame_widget->ReleaseMouseLockAndPointerCaptureForTesting();
if (!web_frame_widget->LocalRoot()->Parent()) {
web_frame_widget->ResetZoomLevelForTesting();
web_frame_widget->SetMainFrameOverlayColor(SK_ColorTRANSPARENT);
web_frame_widget->SetTextZoomFactor(1);
}
}
void TestRunner::SetTestIsRunning(bool running) {
test_is_running_ = running;
}
bool TestRunner::ShouldDumpSelectionRect() const {
return web_test_runtime_flags_.dump_selection_rect();
}
bool TestRunner::ShouldDumpEditingCallbacks() const {
return web_test_runtime_flags_.dump_editting_callbacks();
}
void TestRunner::SetShouldDumpAsLayout(bool value) {
web_test_runtime_flags_.set_dump_as_layout(value);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::ShouldDumpAsCustomText() const {
return web_test_runtime_flags_.has_custom_text_output();
}
std::string TestRunner::CustomDumpText() const {
return web_test_runtime_flags_.custom_text_output();
}
void TestRunner::SetCustomTextOutput(const std::string& text) {
web_test_runtime_flags_.set_custom_text_output(text);
web_test_runtime_flags_.set_has_custom_text_output(true);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::ShouldGeneratePixelResults() {
return web_test_runtime_flags_.generate_pixel_results();
}
TextResultType TestRunner::ShouldGenerateTextResults() {
if (web_test_runtime_flags_.dump_as_text()) {
return TextResultType::kText;
} else if (web_test_runtime_flags_.dump_as_markup()) {
DCHECK(!web_test_runtime_flags_.is_printing());
return TextResultType::kMarkup;
} else if (web_test_runtime_flags_.dump_as_layout()) {
if (web_test_runtime_flags_.is_printing())
return TextResultType::kLayoutAsPrinting;
return TextResultType::kLayout;
}
return TextResultType::kEmpty;
}
bool TestRunner::ShouldStayOnPageAfterHandlingBeforeUnload() const {
return web_test_runtime_flags_.stay_on_page_after_handling_before_unload();
}
void TestRunner::SetShouldGeneratePixelResults(bool value) {
web_test_runtime_flags_.set_generate_pixel_results(value);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::ShouldDumpAsAudio() const {
return dump_as_audio_;
}
const std::vector<uint8_t>& TestRunner::GetAudioData() const {
return audio_data_;
}
bool TestRunner::IsRecursiveLayoutDumpRequested() {
return web_test_runtime_flags_.dump_child_frames();
}
bool TestRunner::CanDumpPixelsFromRenderer() const {
return web_test_runtime_flags_.dump_drag_image() ||
web_test_runtime_flags_.is_printing();
}
#if BUILDFLAG(ENABLE_PRINTING)
gfx::Size TestRunner::GetPrintingPageSize(blink::WebLocalFrame* frame) const {
const int printing_width = web_test_runtime_flags_.printing_width();
const int printing_height = web_test_runtime_flags_.printing_height();
if (printing_width > 0 && printing_height > 0) {
return gfx::Size(printing_width, printing_height);
}
blink::WebFrameWidget* widget = frame->LocalRoot()->FrameWidget();
widget->UpdateAllLifecyclePhases(blink::DocumentUpdateReason::kTest);
return widget->Size();
}
static std::string GetPageRangesStringFromMetadata(
blink::WebLocalFrame* frame) {
blink::WebElementCollection meta_iter =
frame->GetDocument().GetElementsByHTMLTagName("meta");
std::string result = "-";
if (!meta_iter.IsNull()) {
for (blink::WebElement meta = meta_iter.FirstItem(); !meta.IsNull();
meta = meta_iter.NextItem()) {
if (meta.GetAttribute("name") == "reftest-pages") {
blink::WebString pages = meta.GetAttribute("content");
if (!pages.IsNull()) {
result = pages.Ascii();
}
break;
}
}
}
return result;
}
printing::PageRanges TestRunner::GetPrintingPageRanges(
blink::WebLocalFrame* frame) const {
const std::string page_ranges_string = GetPageRangesStringFromMetadata(frame);
const std::vector<base::StringPiece> range_strings =
base::SplitStringPiece(page_ranges_string, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
printing::PageRanges result;
for (const base::StringPiece& range_string : range_strings) {
const std::vector<base::StringPiece> page_strings = base::SplitStringPiece(
range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
bool invalid = false;
if (page_strings.size() == 1) {
uint32_t page;
if (base::StringToUint(range_string, &page)) {
result.push_back(printing::PageRange{.from = page - 1, .to = page - 1});
} else {
invalid = true;
}
} else if (page_strings.size() > 2) {
invalid = true;
} else {
std::array<uint32_t, 2> page_nums{0, printing::PageRange::kMaxPage};
for (const int i : {0, 1}) {
if (!page_strings[i].empty()) {
if (base::StringToUint(page_strings[i], &page_nums[i])) {
--page_nums[i];
} else {
invalid = true;
break;
}
}
}
if (!invalid) {
result.push_back(
printing::PageRange{.from = page_nums[0], .to = page_nums[1]});
}
}
if (invalid) {
DLOG(WARNING) << "Invalid page range \"" << range_string << "\".\n";
}
}
printing::PageRange::Normalize(result);
return result;
}
#endif
SkBitmap TestRunner::DumpPixelsInRenderer(blink::WebLocalFrame* main_frame) {
DCHECK(!main_frame->Parent());
DCHECK(CanDumpPixelsFromRenderer());
if (web_test_runtime_flags_.dump_drag_image()) {
if (!drag_image_.isNull())
return drag_image_;
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(0);
return bitmap;
}
#if BUILDFLAG(ENABLE_PRINTING)
blink::WebLocalFrame* target_frame = main_frame;
std::string frame_name = web_test_runtime_flags_.printing_frame();
if (!frame_name.empty()) {
blink::WebFrame* frame_to_print =
main_frame->FindFrameByName(blink::WebString::FromUTF8(frame_name));
if (frame_to_print && frame_to_print->IsWebLocalFrame())
target_frame = frame_to_print->ToWebLocalFrame();
}
return PrintFrameToBitmap(target_frame, GetPrintingPageSize(target_frame),
GetPrintingPageRanges(target_frame));
#else
NOTREACHED();
return SkBitmap();
#endif
}
void TestRunner::ReplicateWebTestRuntimeFlagsChanges(
const base::Value::Dict& changed_values) {
if (!test_is_running_)
return;
web_test_runtime_flags_.tracked_dictionary().ApplyUntrackedChanges(
changed_values);
}
bool TestRunner::HasCustomTextDump(std::string* custom_text_dump) const {
if (ShouldDumpAsCustomText()) {
*custom_text_dump = CustomDumpText();
return true;
}
return false;
}
bool TestRunner::ShouldDumpFrameLoadCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_frame_load_callbacks();
}
void TestRunner::SetShouldDumpFrameLoadCallbacks(bool value) {
web_test_runtime_flags_.set_dump_frame_load_callbacks(value);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::ShouldDumpPingLoaderCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_ping_loader_callbacks();
}
bool TestRunner::ShouldDumpUserGestureInFrameLoadCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_user_gesture_in_frame_load_callbacks();
}
bool TestRunner::ShouldDumpTitleChanges() const {
return web_test_runtime_flags_.dump_title_changes();
}
bool TestRunner::ShouldDumpIconChanges() const {
return web_test_runtime_flags_.dump_icon_changes();
}
blink::WebContentSettingsClient* TestRunner::GetWebContentSettings() {
return &test_content_settings_client_;
}
bool TestRunner::ShouldDumpBackForwardList() const {
return dump_back_forward_list_;
}
bool TestRunner::ShouldWaitUntilExternalURLLoad() const {
return web_test_runtime_flags_.wait_until_external_url_load();
}
const std::set<std::string>* TestRunner::HttpHeadersToClear() const {
return &http_headers_to_clear_;
}
bool TestRunner::ClearReferrer() const {
return clear_referrer_;
}
void TestRunner::AddLoadingFrame(blink::WebFrame* frame) {
if (!test_is_running_)
return;
if (loading_frames_.empty()) {
if (web_test_runtime_flags_.have_loading_frame())
return;
web_test_runtime_flags_.set_have_loading_frame(true);
OnWebTestRuntimeFlagsChanged();
}
loading_frames_.push_back(frame);
frame_will_start_load_ = false;
}
void TestRunner::RemoveLoadingFrame(blink::WebFrame* frame) {
if (!base::Contains(loading_frames_, frame))
return;
base::Erase(loading_frames_, frame);
if (!loading_frames_.empty())
return;
web_test_runtime_flags_.set_have_loading_frame(false);
if (!test_is_running_)
return;
main_frame_loaded_ = true;
OnWebTestRuntimeFlagsChanged();
work_queue_.set_frozen(true);
work_queue_.OnStatesChanged();
work_queue_.set_loading(false);
if (!web_test_runtime_flags_.wait_until_done() || did_notify_done_)
work_queue_.RequestWork();
}
void TestRunner::OnFrameDeactivated(WebFrameTestProxy* frame) {
if (!test_is_running_)
return;
DCHECK(frame->IsMainFrame());
RemoveMainFrame(frame);
if (frame->GetWebFrame()->IsLoading())
RemoveLoadingFrame(frame->GetWebFrame());
}
void TestRunner::OnFrameReactivated(WebFrameTestProxy* frame) {
if (!test_is_running_)
return;
DCHECK(frame->IsMainFrame());
if (frame->GetWebFrame()->IsLoading()) {
AddLoadingFrame(frame->GetWebFrame());
}
frame_will_start_load_ = false;
AddMainFrame(frame);
if (IsFrameInMainWindow(frame->GetWebFrame())) {
work_queue_.RequestWork();
}
}
void TestRunner::FinishTestIfReady() {
if (!test_is_running_)
return;
if (!main_frame_loaded_ && !did_notify_done_)
return;
if (frame_will_start_load_ || !loading_frames_.empty())
return;
if (work_queue_.has_items())
return;
if (web_test_runtime_flags_.wait_until_done() && !did_notify_done_)
return;
FinishTest();
}
void TestRunner::TestFinishedFromSecondaryRenderer() {
NotifyDone();
}
void TestRunner::ResetRendererAfterWebTest() {
WebFrameTestProxy* main_frame = FindInProcessMainWindowMainFrame();
if (main_frame)
main_frame->Reset();
Reset();
}
void TestRunner::AddMainFrame(WebFrameTestProxy* frame) {
main_frames_.insert(frame);
}
void TestRunner::RemoveMainFrame(WebFrameTestProxy* frame) {
main_frames_.erase(frame);
}
void TestRunner::PolicyDelegateDone() {
DCHECK(web_test_runtime_flags_.wait_until_done());
FinishTest();
}
bool TestRunner::PolicyDelegateEnabled() const {
return web_test_runtime_flags_.policy_delegate_enabled();
}
bool TestRunner::PolicyDelegateIsPermissive() const {
return web_test_runtime_flags_.policy_delegate_is_permissive();
}
bool TestRunner::PolicyDelegateShouldNotifyDone() const {
return web_test_runtime_flags_.policy_delegate_should_notify_done();
}
void TestRunner::SetDragImage(const SkBitmap& drag_image) {
if (web_test_runtime_flags_.dump_drag_image()) {
if (drag_image_.isNull())
drag_image_ = drag_image;
}
}
bool TestRunner::ShouldDumpNavigationPolicy() const {
return web_test_runtime_flags_.dump_navigation_policy();
}
WebFrameTestProxy* TestRunner::FindInProcessMainWindowMainFrame() {
for (WebFrameTestProxy* main_frame : main_frames_) {
if (IsFrameInMainWindow(main_frame->GetWebFrame()))
return main_frame;
}
return nullptr;
}
void TestRunner::WaitUntilDone() {
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::NotifyDone() {
if (!web_test_runtime_flags_.wait_until_done())
return;
if (did_notify_done_)
return;
did_notify_done_ = true;
FinishTestIfReady();
}
void TestRunner::QueueBackNavigation(int how_far_back) {
work_queue_.AddWork(mojom::WorkItem::NewBackForward(
mojom::WorkItemBackForward::New(-how_far_back)));
}
void TestRunner::QueueForwardNavigation(int how_far_forward) {
work_queue_.AddWork(mojom::WorkItem::NewBackForward(
mojom::WorkItemBackForward::New(how_far_forward)));
}
void TestRunner::QueueReload() {
work_queue_.AddWork(mojom::WorkItem::NewReload(mojom::WorkItemReload::New()));
}
void TestRunner::QueueLoadingScript(const std::string& script) {
work_queue_.AddWork(mojom::WorkItem::NewLoadingScript(
mojom::WorkItemLoadingScript::New(script)));
}
void TestRunner::QueueNonLoadingScript(const std::string& script) {
work_queue_.AddWork(mojom::WorkItem::NewNonLoadingScript(
mojom::WorkItemNonLoadingScript::New(script)));
}
void TestRunner::QueueLoad(const GURL& current_url,
const std::string& relative_url,
const std::string& target) {
GURL full_url = current_url.Resolve(relative_url);
work_queue_.AddWork(mojom::WorkItem::NewLoad(
mojom::WorkItemLoad::New(full_url.spec(), target)));
}
void TestRunner::ProcessWorkItem(mojom::WorkItemPtr work_item) {
work_queue_.ProcessWorkItem(std::move(work_item));
}
void TestRunner::ReplicateWorkQueueStates(const base::Value::Dict& values) {
if (!test_is_running_)
return;
work_queue_.ReplicateStates(values);
}
bool TestRunner::IsFrameInMainWindow(blink::WebLocalFrame* frame) {
blink::WebView* view = frame->View();
for (auto& window : main_windows_) {
if (window->GetWebView() == view)
return true;
}
return false;
}
void TestRunner::SetMainWindowAndTestConfiguration(
blink::WebLocalFrame* frame,
mojom::WebTestRunTestConfigurationPtr config) {
blink::WebView* view = frame->View();
if (!IsFrameInMainWindow(frame)) {
main_windows_.push_back(std::make_unique<MainWindowTracker>(view, this));
}
if (test_is_running_)
return;
test_config_ = std::move(*config);
SetTestIsRunning(true);
std::string spec = GURL(test_config_.test_url).spec();
size_t path_start = spec.rfind("web_tests/");
if (path_start != std::string::npos)
spec = spec.substr(path_start);
bool is_devtools_test =
spec.find("/devtools/") != std::string::npos ||
spec.find("/inspector-protocol/") != std::string::npos;
if (is_devtools_test)
SetDumpConsoleMessages(false);
if (!test_config_.protocol_mode)
SetShouldDumpAsLayout(true);
bool wpt_printing_test = test_config_.wpt_print_mode;
if (spec.find("/loading/") != std::string::npos)
SetShouldDumpFrameLoadCallbacks(true);
if (IsWebPlatformTest(spec)) {
SetIsWebPlatformTestsMode();
if (spec.find("/print/") != std::string::npos ||
spec.find("-print.html") != std::string::npos) {
wpt_printing_test = true;
}
}
if (wpt_printing_test) {
SetPrinting();
view->GetSettings()->SetShouldPrintBackgrounds(true);
SetPrintingSize(kWPTPrintWidth, kWPTPrintHeight);
}
view->GetSettings()->SetV8CacheOptions(
is_devtools_test ? blink::mojom::V8CacheOptions::kNone
: blink::mojom::V8CacheOptions::kDefault);
}
blink::WebString TestRunner::GetAbsoluteWebStringFromUTF8Path(
const std::string& utf8_path) {
DCHECK(test_is_running_);
base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path);
if (!path.IsAbsolute()) {
GURL base_url =
net::FilePathToFileURL(test_config_.current_working_directory.Append(
FILE_PATH_LITERAL("foo")));
net::FileURLToFilePath(base_url.Resolve(utf8_path), &path);
}
return blink::FilePathToWebString(path);
}
const mojom::WebTestRunTestConfiguration& TestRunner::TestConfig() const {
DCHECK(test_is_running_);
return test_config_;
}
void TestRunner::OnTestPreferencesChanged(const TestPreferences& test_prefs,
RenderFrame* frame) {
blink::WebView* web_view = frame->GetWebFrame()->View();
blink::web_pref::WebPreferences web_prefs = web_view->GetWebPreferences();
ExportWebTestSpecificPreferences(test_prefs, &web_prefs);
web_view->SetWebPreferences(web_prefs);
GetWebTestControlHostRemote()->OverridePreferences(web_prefs);
}
void TestRunner::SetCustomPolicyDelegate(gin::Arguments* args) {
bool value;
args->GetNext(&value);
web_test_runtime_flags_.set_policy_delegate_enabled(value);
if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsBoolean()) {
args->GetNext(&value);
web_test_runtime_flags_.set_policy_delegate_is_permissive(value);
}
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::WaitForPolicyDelegate() {
web_test_runtime_flags_.set_policy_delegate_enabled(true);
web_test_runtime_flags_.set_policy_delegate_should_notify_done(true);
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged();
}
int TestRunner::InProcessWindowCount() {
return main_frames_.size();
}
void TestRunner::AddOriginAccessAllowListEntry(
const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains) {
blink::WebURL url((GURL(source_origin)));
if (!url.IsValid())
return;
blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
url, blink::WebString::FromUTF8(destination_protocol),
blink::WebString::FromUTF8(destination_host), 0,
allow_destination_subdomains
? network::mojom::CorsDomainMatchMode::kAllowSubdomains
: network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
network::mojom::CorsPortMatchMode::kAllowAnyPort,
network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
}
void TestRunner::SetTextSubpixelPositioning(bool value) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
blink::WebFontRenderStyle::SetSubpixelPositioning(value);
#endif
}
void TestRunner::SetMockScreenOrientation(blink::WebView* view,
const std::string& orientation_str) {
display::mojom::ScreenOrientation orientation;
if (orientation_str == "portrait-primary") {
orientation = display::mojom::ScreenOrientation::kPortraitPrimary;
} else if (orientation_str == "portrait-secondary") {
orientation = display::mojom::ScreenOrientation::kPortraitSecondary;
} else if (orientation_str == "landscape-primary") {
orientation = display::mojom::ScreenOrientation::kLandscapePrimary;
} else {
DCHECK_EQ("landscape-secondary", orientation_str);
orientation = display::mojom::ScreenOrientation::kLandscapeSecondary;
}
bool changed =
fake_screen_orientation_impl_.UpdateDeviceOrientation(view, orientation);
if (changed)
GetWebTestControlHostRemote()->SetScreenOrientationChanged();
}
void TestRunner::DisableMockScreenOrientation(blink::WebView* view) {
fake_screen_orientation_impl_.SetDisabled(view, true);
}
void TestRunner::SetAcceptLanguages(const std::string& accept_languages) {
GetWebTestControlHostRemote()->SetAcceptLanguages(accept_languages);
}
void TestRunner::DumpEditingCallbacks() {
web_test_runtime_flags_.set_dump_editting_callbacks(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpAsMarkup() {
web_test_runtime_flags_.set_dump_as_markup(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpAsText() {
web_test_runtime_flags_.set_dump_as_text(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpAsTextWithPixelResults() {
web_test_runtime_flags_.set_dump_as_text(true);
web_test_runtime_flags_.set_generate_pixel_results(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpAsLayout() {
web_test_runtime_flags_.set_dump_as_layout(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpAsLayoutWithPixelResults() {
web_test_runtime_flags_.set_dump_as_layout(true);
web_test_runtime_flags_.set_generate_pixel_results(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpChildFrames() {
web_test_runtime_flags_.set_dump_child_frames(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpIconChanges() {
web_test_runtime_flags_.set_dump_icon_changes(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetAudioData(const gin::ArrayBufferView& view) {
uint8_t* bytes = static_cast<uint8_t*>(view.bytes());
audio_data_.resize(view.num_bytes());
std::copy(bytes, bytes + view.num_bytes(), audio_data_.begin());
dump_as_audio_ = true;
}
void TestRunner::DumpFrameLoadCallbacks() {
web_test_runtime_flags_.set_dump_frame_load_callbacks(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpPingLoaderCallbacks() {
web_test_runtime_flags_.set_dump_ping_loader_callbacks(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpUserGestureInFrameLoadCallbacks() {
web_test_runtime_flags_.set_dump_user_gesture_in_frame_load_callbacks(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpTitleChanges() {
web_test_runtime_flags_.set_dump_title_changes(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetImagesAllowed(bool allowed) {
web_test_runtime_flags_.set_images_allowed(allowed);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetScriptsAllowed(bool allowed) {
web_test_runtime_flags_.set_scripts_allowed(allowed);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetStorageAllowed(bool allowed) {
web_test_runtime_flags_.set_storage_allowed(allowed);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetAllowRunningOfInsecureContent(bool allowed) {
web_test_runtime_flags_.set_running_insecure_content_allowed(allowed);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpPermissionClientCallbacks() {
web_test_runtime_flags_.set_dump_web_content_settings_client_callbacks(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpBackForwardList() {
dump_back_forward_list_ = true;
}
void TestRunner::DumpSelectionRect() {
web_test_runtime_flags_.set_dump_selection_rect(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetPrinting() {
SetPrintingForFrame("");
}
void TestRunner::SetPrintingForFrame(const std::string& frame_name) {
web_test_runtime_flags_.set_printing_frame(frame_name);
web_test_runtime_flags_.set_is_printing(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetPrintingSize(int width, int height) {
web_test_runtime_flags_.set_printing_width(width);
web_test_runtime_flags_.set_printing_height(height);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetShouldStayOnPageAfterHandlingBeforeUnload(bool value) {
web_test_runtime_flags_.set_stay_on_page_after_handling_before_unload(value);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetWillSendRequestClearHeader(const std::string& header) {
if (!header.empty())
http_headers_to_clear_.insert(header);
}
void TestRunner::SetWillSendRequestClearReferrer() {
clear_referrer_ = true;
}
void TestRunner::WaitUntilExternalURLLoad() {
web_test_runtime_flags_.set_wait_until_external_url_load(true);
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpDragImage() {
web_test_runtime_flags_.set_dump_drag_image(true);
DumpAsTextWithPixelResults();
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::DumpNavigationPolicy() {
web_test_runtime_flags_.set_dump_navigation_policy(true);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetDumpConsoleMessages(bool value) {
web_test_runtime_flags_.set_dump_console_messages(value);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetIsWebPlatformTestsMode() {
web_test_runtime_flags_.set_is_web_platform_tests_mode(true);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::IsWebPlatformTestsMode() const {
return web_test_runtime_flags_.is_web_platform_tests_mode();
}
void TestRunner::SetDumpJavaScriptDialogs(bool value) {
web_test_runtime_flags_.set_dump_javascript_dialogs(value);
OnWebTestRuntimeFlagsChanged();
}
void TestRunner::SetEffectiveConnectionType(
blink::WebEffectiveConnectionType connection_type) {
effective_connection_type_ = connection_type;
}
bool TestRunner::ShouldDumpConsoleMessages() const {
return test_is_running_ && web_test_runtime_flags_.dump_console_messages();
}
void TestRunner::GoToOffset(int offset) {
GetWebTestControlHostRemote()->GoToOffset(offset);
}
void TestRunner::Reload() {
GetWebTestControlHostRemote()->Reload();
}
void TestRunner::LoadURLForFrame(const GURL& url,
const std::string& frame_name) {
GetWebTestControlHostRemote()->LoadURLForFrame(url, frame_name);
}
void TestRunner::PrintMessage(const std::string& message) {
GetWebTestControlHostRemote()->PrintMessage(message);
}
void TestRunner::PrintMessageToStderr(const std::string& message) {
GetWebTestControlHostRemote()->PrintMessageToStderr(message);
}
blink::WebString TestRunner::RegisterIsolatedFileSystem(
const std::vector<base::FilePath>& file_paths) {
std::string filesystem_id;
GetWebTestControlHostRemote()->RegisterIsolatedFileSystem(file_paths,
&filesystem_id);
return blink::WebString::FromUTF8(filesystem_id);
}
void TestRunner::FocusWindow(RenderFrame* main_frame, bool focus) {
if (!main_frame->IsMainFrame())
return;
auto* frame_proxy = static_cast<WebFrameTestProxy*>(main_frame);
blink::WebFrameWidget* widget = frame_proxy->GetLocalRootWebFrameWidget();
if (!focus) {
if (widget->HasFocus()) {
auto* web_view = frame_proxy->GetWebFrame()->View();
web_view->SetIsActive(false);
widget->SetFocus(false);
}
return;
}
for (WebFrameTestProxy* other_main_frame : main_frames_) {
if (other_main_frame != main_frame) {
blink::WebFrameWidget* other_widget =
other_main_frame->GetLocalRootWebFrameWidget();
if (other_widget->HasFocus()) {
auto* other_web_view = other_main_frame->GetWebFrame()->View();
other_web_view->SetIsActive(false);
other_widget->SetFocus(false);
}
}
}
if (!widget->HasFocus()) {
widget->SetFocus(true);
}
}
void TestRunner::SetAnimationRequiresRaster(bool do_raster) {
animation_requires_raster_ = do_raster;
}
void TestRunner::OnWebTestRuntimeFlagsChanged() {
if (!test_is_running_)
return;
if (web_test_runtime_flags_.tracked_dictionary().changed_values().empty())
return;
GetWebTestControlHostRemote()->WebTestRuntimeFlagsChanged(
web_test_runtime_flags_.tracked_dictionary().changed_values().Clone());
web_test_runtime_flags_.tracked_dictionary().ResetChangeTracking();
}
void TestRunner::FinishTest() {
WebFrameTestProxy* main_frame = FindInProcessMainWindowMainFrame();
if (!main_frame) {
if (did_notify_done_)
GetWebTestControlHostRemote()->TestFinishedInSecondaryRenderer();
return;
}
if (!test_is_running_)
return;
test_is_running_ = false;
auto* web_frame = main_frame->GetWebFrame();
web_frame->FrameWidget()->PrepareForFinalLifecyclUpdateForTesting();
web_frame->FrameWidget()->UpdateAllLifecyclePhases(
blink::DocumentUpdateReason::kTest);
auto dump_result = mojom::WebTestRendererDumpResult::New();
bool browser_should_dump_back_forward_list = ShouldDumpBackForwardList();
bool browser_should_dump_pixels = false;
if (ShouldDumpAsAudio()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalAudioDump");
dump_result->audio = GetAudioData();
} else {
TextResultType text_result_type = ShouldGenerateTextResults();
bool pixel_result = ShouldGeneratePixelResults();
std::string spec = GURL(test_config_.test_url).spec();
size_t path_start = spec.rfind("web_tests/");
if (path_start != std::string::npos)
spec = spec.substr(path_start);
std::string mime_type =
web_frame->GetDocumentLoader()->GetWebResponse().MimeType().Utf8();
if (mime_type == "text/plain" ||
spec.find("/dumpAsText/") != std::string::npos) {
text_result_type = TextResultType::kText;
pixel_result = false;
}
std::string custom_text_dump;
if (HasCustomTextDump(&custom_text_dump)) {
dump_result->layout = custom_text_dump + "\n";
} else if (!IsRecursiveLayoutDumpRequested()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalLayoutDump");
dump_result->layout = DumpLayoutAsString(web_frame, text_result_type);
}
if (pixel_result) {
if (CanDumpPixelsFromRenderer()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalPixelsDump");
SkBitmap actual = DumpPixelsInRenderer(web_frame);
DCHECK_GT(actual.info().width(), 0);
DCHECK_GT(actual.info().height(), 0);
base::MD5Digest digest;
base::MD5Sum(actual.getPixels(), actual.computeByteSize(), &digest);
dump_result->actual_pixel_hash = base::MD5DigestToBase16(digest);
if (dump_result->actual_pixel_hash != test_config_.expected_pixel_hash)
dump_result->pixels = std::move(actual);
} else {
browser_should_dump_pixels = true;
if (ShouldDumpSelectionRect()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalSelectionRect");
dump_result->selection_rect =
web_frame->GetSelectionBoundsRectForTesting();
}
}
}
}
GetWebTestControlHostRemote()->InitiateCaptureDump(
std::move(dump_result), browser_should_dump_back_forward_list,
browser_should_dump_pixels);
}
mojo::AssociatedRemote<mojom::WebTestControlHost>&
TestRunner::GetWebTestControlHostRemote() {
if (!web_test_control_host_remote_) {
RenderThread::Get()->GetChannel()->GetRemoteAssociatedInterface(
&web_test_control_host_remote_);
web_test_control_host_remote_.set_disconnect_handler(
base::BindOnce(&TestRunner::HandleWebTestControlHostDisconnected,
base::Unretained(this)));
}
return web_test_control_host_remote_;
}
void TestRunner::HandleWebTestControlHostDisconnected() {
web_test_control_host_remote_.reset();
}
mojom::WebTestBluetoothFakeAdapterSetter&
TestRunner::GetBluetoothFakeAdapterSetter() {
if (!bluetooth_fake_adapter_setter_) {
RenderThread::Get()->BindHostReceiver(
bluetooth_fake_adapter_setter_.BindNewPipeAndPassReceiver());
bluetooth_fake_adapter_setter_.set_disconnect_handler(base::BindOnce(
&TestRunner::HandleBluetoothFakeAdapterSetterDisconnected,
base::Unretained(this)));
}
return *bluetooth_fake_adapter_setter_;
}
void TestRunner::HandleBluetoothFakeAdapterSetterDisconnected() {
bluetooth_fake_adapter_setter_.reset();
}
void TestRunner::DisableAutomaticDragDrop() {
web_test_runtime_flags_.set_auto_drag_drop_enabled(false);
OnWebTestRuntimeFlagsChanged();
}
bool TestRunner::AutomaticDragDropEnabled() {
return web_test_runtime_flags_.auto_drag_drop_enabled();
}
}