From 94c243acd6873a9fd9115f1467093326392f06c0 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sun, 29 Sep 2024 11:44:17 -0400 Subject: [PATCH] LibWeb+WebContent: Partially implement WebDriver's JSON deserialize AO In particular, we need to convert web element references to the actual element. The AO isn't fully implemented because we will need to work out mixing JsonValue types with JS value types, which currently isn't very straight forward with our JSON clone algorithm. --- .../LibWeb/WebDriver/ElementReference.cpp | 19 ++++++++- .../LibWeb/WebDriver/ElementReference.h | 4 +- .../WebContent/WebDriverConnection.cpp | 42 +++++++++++++++++-- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp b/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp index cfc96116f4a..3067454b6a4 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -44,6 +44,23 @@ JsonObject web_element_reference_object(Web::DOM::Node const& element) return object; } +// https://w3c.github.io/webdriver/#dfn-deserialize-a-web-element +ErrorOr, WebDriver::Error> deserialize_web_element(JsonObject const& object) +{ + // 1. If object has no own property web element identifier, return error with error code invalid argument. + if (!object.has_string(web_element_identifier)) + return WebDriver::Error::from_code(WebDriver::ErrorCode::InvalidArgument, "Object is not a web element"); + + // 2. Let reference be the result of getting the web element identifier property from object. + auto reference = extract_web_element_reference(object); + + // 3. Let element be the result of trying to get a known element with session and reference. + auto* element = TRY(get_known_connected_element(reference)); + + // 4. Return success with data element. + return *element; +} + ByteString extract_web_element_reference(JsonObject const& object) { return object.get_byte_string(web_element_identifier).release_value(); diff --git a/Userland/Libraries/LibWeb/WebDriver/ElementReference.h b/Userland/Libraries/LibWeb/WebDriver/ElementReference.h index 88c3c95672b..f4dca3d7a88 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ElementReference.h +++ b/Userland/Libraries/LibWeb/WebDriver/ElementReference.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ namespace Web::WebDriver { ByteString get_or_create_a_web_element_reference(Web::DOM::Node const& element); JsonObject web_element_reference_object(Web::DOM::Node const& element); +ErrorOr, WebDriver::Error> deserialize_web_element(JsonObject const&); ByteString extract_web_element_reference(JsonObject const&); bool represents_a_web_element(JsonValue const& value); ErrorOr get_known_connected_element(StringView element_id); diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index a96d1fdac72..1af05e21202 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -2312,6 +2312,41 @@ ErrorOr WebDriverConnection::find(StartNodeGet return result; } +// https://w3c.github.io/webdriver/#dfn-json-deserialize +static ErrorOr json_deserialize(JS::VM& vm, 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(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::extract_the_script_arguments_from_a_request(JS::VM& vm, JsonValue const& payload) { @@ -2329,9 +2364,10 @@ ErrorOr WebDriverCo // 5. Let arguments be the result of calling the JSON deserialize algorithm with arguments args. auto arguments = JS::MarkedVector { vm.heap() }; - args.for_each([&](auto const& arg) { - arguments.append(JS::JSONObject::parse_json_value(vm, arg)); - }); + TRY(args.try_for_each([&](auto const& arg) -> ErrorOr { + arguments.append(TRY(json_deserialize(vm, arg))); + return {}; + })); // 6. Return success with data script and arguments. return ScriptArguments { move(script), move(arguments) };