LibWeb+WebContent: Implement the WebDriver JSON clone steps for elements

This is needed by WPT to serialize NodeList instances.
This commit is contained in:
Timothy Flynn 2024-09-13 19:41:31 -04:00 committed by Tim Ledbetter
parent 2dc8cad785
commit bf60765903
Notes: github-actions[bot] 2024-09-14 23:57:21 +00:00
5 changed files with 36 additions and 1 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/DOM/ShadowRoot.h>
@ -61,6 +62,13 @@ ErrorOr<Web::DOM::Element*, Web::WebDriver::Error> get_known_connected_element(S
return static_cast<Web::DOM::Element*>(node);
}
// https://w3c.github.io/webdriver/#dfn-is-stale
bool is_element_stale(Web::DOM::Node const& element)
{
// An element is stale if its node document is not the active document or if it is not connected.
return !element.document().is_active() || !element.is_connected();
}
// https://w3c.github.io/webdriver/#dfn-get-or-create-a-shadow-root-reference
ByteString get_or_create_a_shadow_root_reference(Web::DOM::ShadowRoot const& shadow_root)
{

View file

@ -17,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<Web::DOM::Element*, Web::WebDriver::Error> get_known_connected_element(StringView element_id);
bool is_element_stale(Web::DOM::Node const& element);
ByteString get_or_create_a_shadow_root_reference(Web::DOM::ShadowRoot const& shadow_root);
JsonObject shadow_root_reference_object(Web::DOM::ShadowRoot const& shadow_root);

View file

@ -31,6 +31,7 @@
#include <LibWeb/Page/Page.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebDriver/Contexts.h>
#include <LibWeb/WebDriver/ElementReference.h>
#include <LibWeb/WebDriver/ExecuteScript.h>
namespace Web::WebDriver {
@ -109,7 +110,25 @@ static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm
return ExecuteScriptResultType::JavaScriptError;
// FIXME: -> a collection
// FIXME: -> instance of element
// -> instance of element
if (value.is_object() && is<DOM::Element>(value.as_object())) {
auto const& element = static_cast<DOM::Element const&>(value.as_object());
// If the element is stale, return error with error code stale element reference.
if (is_element_stale(element)) {
return ExecuteScriptResultType::StaleElement;
}
// Otherwise:
else {
// 1. Let reference be the web element reference object for session and value.
auto reference = web_element_reference_object(element);
// 2. Return success with data reference.
return reference;
}
}
// FIXME: -> instance of shadow root
// -> a WindowProxy object

View file

@ -21,6 +21,7 @@ enum class ExecuteScriptResultType {
Timeout,
JavaScriptError,
BrowsingContextDiscarded,
StaleElement,
};
struct ExecuteScriptResult {

View file

@ -1783,6 +1783,9 @@ Messages::WebDriverClient::ExecuteScriptResponse WebDriverConnection::execute_sc
case Web::WebDriver::ExecuteScriptResultType::BrowsingContextDiscarded:
response = Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, "Browsing context has been discarded", move(result.value));
break;
case Web::WebDriver::ExecuteScriptResultType::StaleElement:
response = Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, "Referenced element has become stale", move(result.value));
break;
}
async_script_executed(move(response));
@ -1831,6 +1834,9 @@ Messages::WebDriverClient::ExecuteAsyncScriptResponse WebDriverConnection::execu
case Web::WebDriver::ExecuteScriptResultType::BrowsingContextDiscarded:
response = Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, "Browsing context has been discarded", move(result.value));
break;
case Web::WebDriver::ExecuteScriptResultType::StaleElement:
response = Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, "Referenced element has become stale", move(result.value));
break;
}
async_script_executed(move(response));