From 440c2fa43ce655e1fc0c95370089a4e444bf191a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 13 Sep 2024 19:44:12 -0400 Subject: [PATCH] LibWeb+WebContent: Partially implement the switch-to-frame endpoint This is needed by the cookie tests for WPT. (cherry picked from commit 60fa3752ee8c6eecc1e338c8ebebba2e288eea35) --- .../LibWeb/WebDriver/ElementReference.cpp | 14 +++++ .../LibWeb/WebDriver/ElementReference.h | 1 + .../WebContent/WebDriverConnection.cpp | 63 +++++++++++-------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp b/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp index 9982d4310229a1..f0fc2f657e1ad9 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ElementReference.cpp @@ -45,6 +45,20 @@ JsonObject web_element_reference_object(Web::DOM::Node const& element) return object; } +// https://w3c.github.io/webdriver/#dfn-represents-a-web-element +bool represents_a_web_element(JsonValue const& value) +{ + // An ECMAScript Object represents a web element if it has a web element identifier own property. + if (!value.is_object()) + return false; + + auto const& object = value.as_object(); + if (!object.has_string("name"sv) || !object.has_string("value"sv)) + return false; + + return object.get_byte_string("name"sv) == web_element_identifier; +} + // https://w3c.github.io/webdriver/#dfn-get-a-known-connected-element ErrorOr get_known_connected_element(StringView element_id) { diff --git a/Userland/Libraries/LibWeb/WebDriver/ElementReference.h b/Userland/Libraries/LibWeb/WebDriver/ElementReference.h index b7779a9d98af32..5ac4123af87818 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ElementReference.h +++ b/Userland/Libraries/LibWeb/WebDriver/ElementReference.h @@ -16,6 +16,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); +bool represents_a_web_element(JsonValue const& value); ErrorOr get_known_connected_element(StringView element_id); bool is_element_stale(Web::DOM::Node const& element); diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index 91affd9d961f84..330176a4a609a3 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -504,62 +506,73 @@ Messages::WebDriverClient::NewWindowResponse WebDriverConnection::new_window(Jso } // 11.6 Switch To Frame, https://w3c.github.io/webdriver/#dfn-switch-to-frame -Messages::WebDriverClient::SwitchToFrameResponse WebDriverConnection::switch_to_frame(JsonValue const&) +Messages::WebDriverClient::SwitchToFrameResponse WebDriverConnection::switch_to_frame(JsonValue const& payload) { - dbgln("FIXME: WebDriverConnection::switch_to_frame()"); + // 1. Let id be the result of getting the property "id" from parameters. + if (!payload.is_object() || !payload.as_object().has("id"sv)) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload doesn't have property `id`"sv); - // FIXME: 1. Let id be the result of getting the property "id" from parameters. + auto id = payload.as_object().get("id"sv).release_value(); - // FIXME: 2. If id is not null, a Number object, or an Object that represents a web element, return error with error code invalid argument. + // 2. If id is not null, a Number object, or an Object that represents a web element, return error with error code invalid argument. + if (!id.is_null() && !id.is_number() && !Web::WebDriver::represents_a_web_element(id)) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload property `id` is not null, a number, or a web element"sv); - // FIXME: 3. Run the substeps of the first matching condition: + // 3. Run the substeps of the first matching condition: // -> id is null - - { + if (id.is_null()) { // FIXME: 1. If session's current top-level browsing context is no longer open, return error with error code no such window. - // FIXME: 2. Try to handle any user prompts with session. - // FIXME: 3. Set the current browsing context with session and session's current top-level browsing context. + dbgln("FIXME: WebDriverConnection::switch_to_frame(id=null)"); } // -> id is a Number object - - { + else if (id.is_number()) { // FIXME: 1. If id is less than 0 or greater than 216 – 1, return error with error code invalid argument. - // FIXME: 2. If session's current browsing context is no longer open, return error with error code no such window. - // FIXME: 3. Try to handle any user prompts with session. - // FIXME: 4. Let window be the associated window of session's current browsing context's active document. - // FIXME: 5. If id is not a supported property index of window, return error with error code no such frame. - // FIXME: 6. Let child window be the WindowProxy object obtained by calling window.[[GetOwnProperty]] (id). - // FIXME: 7. Set the current browsing context with session and child window's browsing context. + dbgln("FIXME: WebDriverConnection::switch_to_frame(id={})", id); } // -> id represents a web element + else if (id.is_object()) { + auto element_id = id.as_object().get_byte_string("value"sv).release_value(); - { - // FIXME: 1. If session's current browsing context is no longer open, return error with error code no such window. + // 1. If session's current browsing context is no longer open, return error with error code no such window. + TRY(ensure_current_browsing_context_is_open()); - // FIXME: 2. Try to handle any user prompts with session. + // 2. Try to handle any user prompts with session. + TRY(handle_any_user_prompts()); + + // 3. Let element be the result of trying to get a known element with session and id. + auto* element = TRY(Web::WebDriver::get_known_connected_element(element_id)); - // FIXME: 3. Let element be the result of trying to get a known element with session and id. + // 4. If element is not a frame or iframe element, return error with error code no such frame. + bool is_frame = is(element); + bool is_iframe = is(element); - // FIXME: 4. If element is not a frame or iframe element, return error with error code no such frame. + if (!is_frame && !is_iframe) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchFrame, "element is not a frame"sv); - // FIXME: 5. Set the current browsing context with session and element's content navigable's active browsing context. + // 5. Set the current browsing context with session and element's content navigable's active browsing context. + if (is_frame) { + // FIXME: Should HTMLFrameElement also be a NavigableContainer? + m_current_browsing_context = *element->navigable()->active_browsing_context(); + } else { + auto& navigable_container = static_cast(*element); + m_current_browsing_context = navigable_container.content_navigable()->active_browsing_context(); + } } // FIXME: 4. Update any implementation-specific state that would result from the user selecting session's current browsing context for interaction, without altering OS-level focus. - // FIXME: 5. Return success with data null - + // 5. Return success with data null return JsonValue {}; }