mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
LibWeb+WebContent: Fully implement WebDriver JSON deserialization
This commit is contained in:
parent
7e1caf30a7
commit
fd3f8b7645
Notes:
github-actions[bot]
2024-11-03 17:08:21 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/fd3f8b76450 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2137
3 changed files with 93 additions and 49 deletions
|
@ -12,7 +12,9 @@
|
|||
#include <AK/NumericLimits.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/JSONObject.h>
|
||||
#include <LibWeb/DOM/DOMTokenList.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/HTMLCollection.h>
|
||||
#include <LibWeb/DOM/NodeList.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
|
@ -66,9 +68,13 @@ static bool is_collection(JS::Object const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-clone-an-object
|
||||
static Response clone_an_object(HTML::BrowsingContext const& browsing_context, JS::Object const& value, SeenMap& seen, auto const& clone_algorithm)
|
||||
template<typename ResultType, typename CloneAlgorithm>
|
||||
static ErrorOr<ResultType, WebDriver::Error> clone_an_object(HTML::BrowsingContext const& browsing_context, JS::Object const& value, SeenMap& seen, CloneAlgorithm const& clone_algorithm)
|
||||
{
|
||||
auto& vm = browsing_context.vm();
|
||||
static constexpr bool is_json_value = IsSame<ResultType, JsonValue>;
|
||||
|
||||
auto& realm = browsing_context.active_document()->realm();
|
||||
auto& vm = realm.vm();
|
||||
|
||||
// 1. If value is in seen, return error with error code javascript error.
|
||||
if (seen.contains(value))
|
||||
|
@ -78,7 +84,7 @@ static Response clone_an_object(HTML::BrowsingContext const& browsing_context, J
|
|||
seen.set(value);
|
||||
|
||||
// 3. Let result be the value of the first matching statement, matching on value:
|
||||
auto result = TRY(([&]() -> Response {
|
||||
auto result = TRY(([&]() -> ErrorOr<ResultType, WebDriver::Error> {
|
||||
// -> a collection
|
||||
if (is_collection(value)) {
|
||||
// A new Array which length property is equal to the result of getting the property length of value.
|
||||
|
@ -88,12 +94,18 @@ static Response clone_an_object(HTML::BrowsingContext const& browsing_context, J
|
|||
if (length > NumericLimits<u32>::max())
|
||||
return WebDriver::Error::from_code(ErrorCode::JavascriptError, "Length of Object too large"sv);
|
||||
|
||||
return JsonValue { JsonArray { length } };
|
||||
if constexpr (is_json_value)
|
||||
return JsonArray { length };
|
||||
else
|
||||
return TRY_OR_JS_ERROR(JS::Array::create(realm, length));
|
||||
}
|
||||
// -> Otherwise
|
||||
else {
|
||||
// A new Object.
|
||||
return JsonValue { JsonObject {} };
|
||||
if constexpr (is_json_value)
|
||||
return JsonObject {};
|
||||
else
|
||||
return JS::Object::create(realm, realm.intrinsics().object_prototype());
|
||||
}
|
||||
}()));
|
||||
|
||||
|
@ -119,10 +131,14 @@ static Response clone_an_object(HTML::BrowsingContext const& browsing_context, J
|
|||
// 4. If cloned property result is a success, set a property of result with name name and value equal to cloned
|
||||
// property result's data.
|
||||
if (!cloned_property_result.is_error()) {
|
||||
if (result.is_array() && name.is_number())
|
||||
result.as_array().set(name.as_number(), cloned_property_result.value());
|
||||
else if (result.is_object())
|
||||
result.as_object().set(name.to_string(), cloned_property_result.value());
|
||||
if constexpr (is_json_value) {
|
||||
if (result.is_array() && name.is_number())
|
||||
result.as_array().set(name.as_number(), cloned_property_result.value());
|
||||
else if (result.is_object())
|
||||
result.as_object().set(name.to_string(), cloned_property_result.value());
|
||||
} else {
|
||||
(void)result->set(name, cloned_property_result.value(), JS::Object::ShouldThrowExceptions::No);
|
||||
}
|
||||
}
|
||||
// 5. Otherwise, return cloned property result.
|
||||
else {
|
||||
|
@ -246,7 +262,7 @@ static Response internal_json_clone(HTML::BrowsingContext const& browsing_contex
|
|||
|
||||
// -> Otherwise
|
||||
// 1. Let result be clone an object with session value and seen, and internal JSON clone as the clone algorithm.
|
||||
auto result = TRY(clone_an_object(browsing_context, object, seen, internal_json_clone));
|
||||
auto result = TRY(clone_an_object<JsonValue>(browsing_context, object, seen, internal_json_clone));
|
||||
|
||||
// 2. Return success with data result.
|
||||
return result;
|
||||
|
@ -261,4 +277,64 @@ Response json_clone(HTML::BrowsingContext const& browsing_context, JS::Value val
|
|||
return internal_json_clone(browsing_context, value, seen);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-json-deserialize
|
||||
static ErrorOr<JS::Value, WebDriver::Error> internal_json_deserialize(HTML::BrowsingContext const& browsing_context, JS::Value value, SeenMap& seen)
|
||||
{
|
||||
// 1. If seen is not provided, let seen be an empty List.
|
||||
// 2. Jump to the first appropriate step below:
|
||||
// 3. Matching on value:
|
||||
// -> undefined
|
||||
// -> null
|
||||
// -> type Boolean
|
||||
// -> type Number
|
||||
// -> type String
|
||||
if (value.is_nullish() || value.is_boolean() || value.is_number() || value.is_string()) {
|
||||
// Return success with data value.
|
||||
return value;
|
||||
}
|
||||
|
||||
// -> Object that represents a web element
|
||||
if (represents_a_web_element(value)) {
|
||||
// Return the deserialized web element of value.
|
||||
return deserialize_web_element(browsing_context, value.as_object());
|
||||
}
|
||||
|
||||
// -> Object that represents a shadow root
|
||||
if (represents_a_shadow_root(value)) {
|
||||
// Return the deserialized shadow root of value.
|
||||
return deserialize_shadow_root(browsing_context, value.as_object());
|
||||
}
|
||||
|
||||
// -> Object that represents a web frame
|
||||
if (represents_a_web_frame(value)) {
|
||||
// Return the deserialized web frame of value.
|
||||
return deserialize_web_frame(value.as_object());
|
||||
}
|
||||
|
||||
// -> Object that represents a web window
|
||||
if (represents_a_web_window(value)) {
|
||||
// Return the deserialized web window of value.
|
||||
return deserialize_web_window(value.as_object());
|
||||
}
|
||||
|
||||
// -> instance of Array
|
||||
// -> instance of Object
|
||||
if (value.is_object()) {
|
||||
// Return clone an object algorithm with session, value and seen, and the JSON deserialize algorithm as the
|
||||
// clone algorithm.
|
||||
return clone_an_object<JS::NonnullGCPtr<JS::Object>>(browsing_context, value.as_object(), seen, internal_json_deserialize);
|
||||
}
|
||||
|
||||
return WebDriver::Error::from_code(ErrorCode::JavascriptError, "Unrecognized value type"sv);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-json-deserialize
|
||||
ErrorOr<JS::Value, WebDriver::Error> json_deserialize(HTML::BrowsingContext const& browsing_context, JsonValue const& value)
|
||||
{
|
||||
auto& vm = browsing_context.vm();
|
||||
|
||||
SeenMap seen;
|
||||
return internal_json_deserialize(browsing_context, JS::JSONObject::parse_json_value(vm, value), seen);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
namespace Web::WebDriver {
|
||||
|
||||
Response json_clone(HTML::BrowsingContext const&, JS::Value);
|
||||
ErrorOr<JS::Value, WebDriver::Error> json_deserialize(HTML::BrowsingContext const&, JsonValue const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <AK/Time.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibJS/Runtime/JSONObject.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/CSS/CSSStyleValue.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
|
@ -2816,41 +2815,6 @@ void WebDriverConnection::find(Web::WebDriver::LocationStrategy location_strateg
|
|||
m_element_locator->search_for_element();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-json-deserialize
|
||||
static ErrorOr<JS::Value, Web::WebDriver::Error> json_deserialize(JS::VM& vm, Web::HTML::BrowsingContext const& browsing_context, JsonValue const& value)
|
||||
{
|
||||
// 1. If seen is not provided, let seen be an empty List.
|
||||
// 2. Jump to the first appropriate step below:
|
||||
// 3. Matching on value:
|
||||
// -> undefined
|
||||
// -> null
|
||||
// -> type Boolean
|
||||
// -> type Number
|
||||
// -> type String
|
||||
if (value.is_null() || value.is_bool() || value.is_number() || value.is_string()) {
|
||||
// Return success with data value.
|
||||
return JS::JSONObject::parse_json_value(vm, value);
|
||||
}
|
||||
|
||||
// -> Object that represents a web element
|
||||
if (Web::WebDriver::represents_a_web_element(value)) {
|
||||
// Return the deserialized web element of value.
|
||||
return Web::WebDriver::deserialize_web_element(browsing_context, value.as_object());
|
||||
}
|
||||
|
||||
// FIXME: -> Object that represents a shadow root
|
||||
// Return the deserialized shadow root of value.
|
||||
// FIXME: -> Object that represents a web frame
|
||||
// Return the deserialized web frame of value.
|
||||
// FIXME: -> Object that represents a web window
|
||||
// Return the deserialized web window of value.
|
||||
// FIXME: -> instance of Array
|
||||
// FIXME: -> instance of Object
|
||||
// Return clone an object algorithm with session, value and seen, and the JSON deserialize algorithm as the clone algorithm.
|
||||
dbgln("FIXME: Implement JSON deserialize for: {}", value);
|
||||
return JS::JSONObject::parse_json_value(vm, value);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-extract-the-script-arguments-from-a-request
|
||||
ErrorOr<WebDriverConnection::ScriptArguments, Web::WebDriver::Error> WebDriverConnection::extract_the_script_arguments_from_a_request(JS::VM& vm, JsonValue const& payload)
|
||||
{
|
||||
|
@ -2866,10 +2830,13 @@ ErrorOr<WebDriverConnection::ScriptArguments, Web::WebDriver::Error> WebDriverCo
|
|||
auto const& args = *TRY(Web::WebDriver::get_property<JsonArray const*>(payload, "args"sv));
|
||||
|
||||
// 5. Let arguments be the result of calling the JSON deserialize algorithm with arguments args.
|
||||
auto arguments = JS::MarkedVector<JS::Value> { vm.heap() };
|
||||
JS::MarkedVector<JS::Value> arguments { vm.heap() };
|
||||
auto& browsing_context = current_browsing_context();
|
||||
|
||||
TRY(args.try_for_each([&](JsonValue const& arg) -> ErrorOr<void, Web::WebDriver::Error> {
|
||||
auto deserialized = TRY(Web::WebDriver::json_deserialize(browsing_context, arg));
|
||||
arguments.append(deserialized);
|
||||
|
||||
TRY(args.try_for_each([&](auto const& arg) -> ErrorOr<void, Web::WebDriver::Error> {
|
||||
arguments.append(TRY(json_deserialize(vm, current_browsing_context(), arg)));
|
||||
return {};
|
||||
}));
|
||||
|
||||
|
|
Loading…
Reference in a new issue