LibWeb: Implement WebDriver element references according to the spec

Our currently ad-hoc method of tracking element references is basically
a process-wide map, rather than grouping elements according to their
browsing context groups. This prevents us from recognizing when an
element reference is invalid due to its browsing context having been
closed.

This implements the WebDriver spec concept of element references grouped
according to their browsing context groups.

This patch is a bit noisy because we now need to plumb the current BC
through to the element reference AOs.
This commit is contained in:
Timothy Flynn 2024-10-24 13:23:38 -04:00 committed by Tim Flynn
parent ede6924db8
commit a9c858fc78
Notes: github-actions[bot] 2024-10-24 23:01:12 +00:00
8 changed files with 155 additions and 67 deletions

View file

@ -397,6 +397,11 @@ BrowsingContextGroup* BrowsingContext::group()
return m_group;
}
BrowsingContextGroup const* BrowsingContext::group() const
{
return m_group;
}
void BrowsingContext::set_group(BrowsingContextGroup* group)
{
m_group = group;

View file

@ -117,6 +117,7 @@ public:
JS::GCPtr<BrowsingContext> top_level_browsing_context() const;
BrowsingContextGroup* group();
BrowsingContextGroup const* group() const;
void set_group(BrowsingContextGroup*);
// https://html.spec.whatwg.org/multipage/browsers.html#bcg-remove

View file

@ -200,7 +200,7 @@ static ErrorOr<CSSPixelPoint, WebDriver::Error> get_coordinates_relative_to_orig
// 1. Let element be the result of trying to run actions options' get element origin steps with origin and
// browsing context.
// 2. If element is null, return error with error code no such element.
auto element = TRY(actions_options.get_element_origin(origin));
auto element = TRY(actions_options.get_element_origin(browsing_context, origin));
// 3. Let x element and y element be the result of calculating the in-view center point of element.
auto position = in_view_center_point(element, viewport);

View file

@ -119,7 +119,7 @@ struct ActionObject {
// https://w3c.github.io/webdriver/#dfn-actions-options
struct ActionsOptions {
Function<bool(JsonObject const&)> is_element_origin;
Function<ErrorOr<JS::NonnullGCPtr<DOM::Element>, WebDriver::Error>(StringView)> get_element_origin;
Function<ErrorOr<JS::NonnullGCPtr<DOM::Element>, WebDriver::Error>(HTML::BrowsingContext const&, StringView)> get_element_origin;
};
using OnActionsComplete = JS::NonnullGCPtr<JS::HeapFunction<void(Web::WebDriver::Response)>>;

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/HashMap.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/Node.h>
@ -11,6 +12,7 @@
#include <LibWeb/Geometry/DOMRect.h>
#include <LibWeb/Geometry/DOMRectList.h>
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/BrowsingContextGroup.h>
#include <LibWeb/HTML/HTMLBodyElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/HTML/HTMLTextAreaElement.h>
@ -27,25 +29,105 @@ static ByteString const web_element_identifier = "element-6066-11e4-a52e-4f73546
// https://w3c.github.io/webdriver/#dfn-shadow-root-identifier
static ByteString const shadow_root_identifier = "shadow-6066-11e4-a52e-4f735466cecf"sv;
// https://w3c.github.io/webdriver/#dfn-get-or-create-a-web-element-reference
ByteString get_or_create_a_web_element_reference(Web::DOM::Node const& element)
{
// FIXME: 1. For each known element of the current browsing contexts list of known elements:
// FIXME: 1. If known element equals element, return success with known elements web element reference.
// FIXME: 2. Add element to the list of known elements of the current browsing context.
// FIXME: 3. Return success with the elements web element reference.
// https://w3c.github.io/webdriver/#dfn-browsing-context-group-node-map
static HashMap<JS::RawGCPtr<HTML::BrowsingContextGroup const>, HashTable<ByteString>> browsing_context_group_node_map;
return ByteString::number(element.unique_id().value());
// https://w3c.github.io/webdriver/#dfn-navigable-seen-nodes-map
static HashMap<JS::RawGCPtr<HTML::Navigable>, HashTable<ByteString>> navigable_seen_nodes_map;
// https://w3c.github.io/webdriver/#dfn-get-a-node
JS::GCPtr<Web::DOM::Node> get_node(HTML::BrowsingContext const& browsing_context, StringView reference)
{
// 1. Let browsing context group node map be session's browsing context group node map.
// 2. Let browsing context group be browsing context's browsing context group.
auto const* browsing_context_group = browsing_context.group();
// 3. If browsing context group node map does not contain browsing context group, return null.
// 4. Let node id map be browsing context group node map[browsing context group].
auto node_id_map = browsing_context_group_node_map.get(browsing_context_group);
if (!node_id_map.has_value())
return nullptr;
// 5. Let node be the entry in node id map whose value is reference, if such an entry exists, or null otherwise.
JS::GCPtr<Web::DOM::Node> node;
if (node_id_map->contains(reference)) {
auto node_id = reference.to_number<i64>().value();
node = Web::DOM::Node::from_unique_id(UniqueNodeID(node_id));
}
// 6. Return node.
return node;
}
// https://w3c.github.io/webdriver/#dfn-get-or-create-a-node-reference
ByteString get_or_create_a_node_reference(HTML::BrowsingContext const& browsing_context, Web::DOM::Node const& node)
{
// 1. Let browsing context group node map be session's browsing context group node map.
// 2. Let browsing context group be browsing context's browsing context group.
auto const* browsing_context_group = browsing_context.group();
// 3. If browsing context group node map does not contain browsing context group, set browsing context group node
// map[browsing context group] to a new weak map.
// 4. Let node id map be browsing context group node map[browsing context group].
auto& node_id_map = browsing_context_group_node_map.ensure(browsing_context_group);
auto node_id = ByteString::number(node.unique_id().value());
// 5. If node id map does not contain node:
if (!node_id_map.contains(node_id)) {
// 1. Let node id be a new globally unique string.
// 2. Set node id map[node] to node id.
node_id_map.set(node_id);
// 3. Let navigable be browsing context's active document's node navigable.
auto navigable = browsing_context.active_document()->navigable();
// 4. Let navigable seen nodes map be session's navigable seen nodes map.
// 5. If navigable seen nodes map does not contain navigable, set navigable seen nodes map[navigable] to an empty set.
// 6. Append node id to navigable seen nodes map[navigable].
navigable_seen_nodes_map.ensure(navigable).set(node_id);
}
// 6. Return node id map[node].
return node_id;
}
// https://w3c.github.io/webdriver/#dfn-node-reference-is-known
bool node_reference_is_known(HTML::BrowsingContext const& browsing_context, StringView reference)
{
// 1. Let navigable be browsing context's active document's node navigable.
auto navigable = browsing_context.active_document()->navigable();
if (!navigable)
return false;
// 2. Let navigable seen nodes map be session's navigable seen nodes map.
// 3. If navigable seen nodes map contains navigable and navigable seen nodes map[navigable] contains reference,
// return true, otherwise return false.
if (auto map = navigable_seen_nodes_map.get(navigable); map.has_value())
return map->contains(reference);
return false;
}
// https://w3c.github.io/webdriver/#dfn-get-or-create-a-web-element-reference
ByteString get_or_create_a_web_element_reference(HTML::BrowsingContext const& browsing_context, Web::DOM::Node const& element)
{
// 1. Assert: element implements Element.
VERIFY(element.is_element());
// 2. Return the result of trying to get or create a node reference given session, session's current browsing
// context, and element.
return get_or_create_a_node_reference(browsing_context, element);
}
// https://w3c.github.io/webdriver/#dfn-web-element-reference-object
JsonObject web_element_reference_object(Web::DOM::Node const& element)
JsonObject web_element_reference_object(HTML::BrowsingContext const& browsing_context, Web::DOM::Node const& element)
{
// 1. Let identifier be the web element identifier.
auto identifier = web_element_identifier;
// 2. Let reference be the result of get or create a web element reference given element.
auto reference = get_or_create_a_web_element_reference(element);
auto reference = get_or_create_a_web_element_reference(browsing_context, element);
// 3. Return a JSON Object initialized with a property with name identifier and value reference.
JsonObject object;
@ -54,7 +136,7 @@ JsonObject web_element_reference_object(Web::DOM::Node const& element)
}
// https://w3c.github.io/webdriver/#dfn-deserialize-a-web-element
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, WebDriver::Error> deserialize_web_element(JsonObject const& object)
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, WebDriver::Error> deserialize_web_element(Web::HTML::BrowsingContext const& browsing_context, 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))
@ -64,10 +146,10 @@ ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, WebDriver::Error> deserialize_web_e
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_element(reference));
auto element = TRY(get_known_element(browsing_context, reference));
// 4. Return success with data element.
return *element;
return element;
}
ByteString extract_web_element_reference(JsonObject const& object)
@ -85,39 +167,35 @@ bool represents_a_web_element(JsonValue const& value)
}
// https://w3c.github.io/webdriver/#dfn-get-a-webelement-origin
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_web_element_origin(StringView origin)
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_web_element_origin(Web::HTML::BrowsingContext const& browsing_context, StringView origin)
{
// 1. Assert: browsing context is the current browsing context.
// 2. Let element be equal to the result of trying to get a known element with session and origin.
auto element = TRY(get_known_element(origin));
auto element = TRY(get_known_element(browsing_context, origin));
// 3. Return success with data element.
return element;
}
// https://w3c.github.io/webdriver/#dfn-get-a-known-element
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_known_element(StringView element_id)
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_known_element(Web::HTML::BrowsingContext const& browsing_context, StringView reference)
{
// NOTE: The whole concept of "connected elements" is not implemented yet. See get_or_create_a_web_element_reference().
// For now the element is only represented by its ID.
// 1. If not node reference is known with session, session's current browsing context, and reference return error
// with error code no such element.
auto element = element_id.to_number<i64>();
if (!element.has_value())
if (!node_reference_is_known(browsing_context, reference))
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchElement, "Element ID is not an integer");
// 2. Let node be the result of get a node with session, session's current browsing context, and reference.
auto* node = Web::DOM::Node::from_unique_id(UniqueNodeID(*element));
auto node = get_node(browsing_context, reference);
// 3. If node is not null and node does not implement Element return error with error code no such element.
if (node && !node->is_element())
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchElement, ByteString::formatted("Could not find element with ID: {}", element_id));
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchElement, ByteString::formatted("Could not find element with node reference: {}", reference));
// 4. If node is null or node is stale return error with error code stale element reference.
if (!node || is_element_stale(*node))
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, ByteString::formatted("Element with ID: {} is stale", element_id));
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::StaleElementReference, ByteString::formatted("Element reference {} is stale", reference));
// 5. Return success with data node.
return static_cast<Web::DOM::Element&>(*node);

View file

@ -16,13 +16,17 @@
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<JS::NonnullGCPtr<Web::DOM::Element>, WebDriver::Error> deserialize_web_element(JsonObject const&);
JS::GCPtr<Web::DOM::Node> get_node(HTML::BrowsingContext const&, StringView reference);
ByteString get_or_create_a_node_reference(HTML::BrowsingContext const&, Web::DOM::Node const&);
bool node_reference_is_known(HTML::BrowsingContext const&, StringView reference);
ByteString get_or_create_a_web_element_reference(HTML::BrowsingContext const&, Web::DOM::Node const& element);
JsonObject web_element_reference_object(HTML::BrowsingContext const&, Web::DOM::Node const& element);
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, WebDriver::Error> deserialize_web_element(Web::HTML::BrowsingContext const&, JsonObject const&);
ByteString extract_web_element_reference(JsonObject const&);
bool represents_a_web_element(JsonValue const& value);
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_web_element_origin(StringView origin);
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_known_element(StringView element_id);
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_web_element_origin(Web::HTML::BrowsingContext const&, StringView origin);
ErrorOr<JS::NonnullGCPtr<Web::DOM::Element>, Web::WebDriver::Error> get_known_element(Web::HTML::BrowsingContext const&, StringView reference);
bool is_element_stale(Web::DOM::Node const& element);
bool is_element_interactable(Web::HTML::BrowsingContext const&, Web::DOM::Element const&);

View file

@ -46,8 +46,8 @@ namespace Web::WebDriver {
_temporary_result.release_value(); \
})
static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm(JS::Realm&, JS::Value, HashTable<JS::Object*>& seen);
static ErrorOr<JsonValue, ExecuteScriptResultType> clone_an_object(JS::Realm&, JS::Object&, HashTable<JS::Object*>& seen, auto const& clone_algorithm);
static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm(JS::Realm&, HTML::BrowsingContext const&, JS::Value, HashTable<JS::Object*>& seen);
static ErrorOr<JsonValue, ExecuteScriptResultType> clone_an_object(JS::Realm&, HTML::BrowsingContext const&, JS::Object&, HashTable<JS::Object*>& seen, auto const& clone_algorithm);
// https://w3c.github.io/webdriver/#dfn-collection
static bool is_collection(JS::Object const& value)
@ -73,15 +73,15 @@ static bool is_collection(JS::Object const& value)
}
// https://w3c.github.io/webdriver/#dfn-json-clone
static ErrorOr<JsonValue, ExecuteScriptResultType> json_clone(JS::Realm& realm, JS::Value value)
static ErrorOr<JsonValue, ExecuteScriptResultType> json_clone(JS::Realm& realm, HTML::BrowsingContext const& browsing_context, JS::Value value)
{
// To perform a JSON clone return the result of calling the internal JSON clone algorithm with arguments value and an empty List.
auto seen = HashTable<JS::Object*> {};
return internal_json_clone_algorithm(realm, value, seen);
return internal_json_clone_algorithm(realm, browsing_context, value, seen);
}
// https://w3c.github.io/webdriver/#dfn-internal-json-clone-algorithm
static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm(JS::Realm& realm, JS::Value value, HashTable<JS::Object*>& seen)
static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm(JS::Realm& realm, HTML::BrowsingContext const& browsing_context, JS::Value value, HashTable<JS::Object*>& seen)
{
auto& vm = realm.vm();
@ -122,7 +122,7 @@ static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm
// Otherwise:
else {
// 1. Let reference be the web element reference object for session and value.
auto reference = web_element_reference_object(element);
auto reference = web_element_reference_object(browsing_context, element);
// 2. Return success with data reference.
return reference;
@ -168,14 +168,14 @@ static ErrorOr<JsonValue, ExecuteScriptResultType> internal_json_clone_algorithm
} };
// 3. Let result be the value of running the clone an object algorithm with arguments value and seen, and the internal JSON clone algorithm as the clone algorithm.
auto result = TRY(clone_an_object(realm, value.as_object(), seen, internal_json_clone_algorithm));
auto result = TRY(clone_an_object(realm, browsing_context, value.as_object(), seen, internal_json_clone_algorithm));
// 5. Return result.
return result;
}
// https://w3c.github.io/webdriver/#dfn-clone-an-object
static ErrorOr<JsonValue, ExecuteScriptResultType> clone_an_object(JS::Realm& realm, JS::Object& value, HashTable<JS::Object*>& seen, auto const& clone_algorithm)
static ErrorOr<JsonValue, ExecuteScriptResultType> clone_an_object(JS::Realm& realm, HTML::BrowsingContext const& browsing_context, JS::Object& value, HashTable<JS::Object*>& seen, auto const& clone_algorithm)
{
auto& vm = realm.vm();
@ -217,7 +217,7 @@ static ErrorOr<JsonValue, ExecuteScriptResultType> clone_an_object(JS::Realm& re
continue;
// 3. Let cloned property result be the result of calling the clone algorithm with arguments source property value and seen.
auto cloned_property_result = clone_algorithm(realm, *source_property_value->value, seen);
auto cloned_property_result = clone_algorithm(realm, browsing_context, *source_property_value->value, seen);
// 4. If cloned property result is a success, set a property of result with name name and value equal to cloned property results data.
if (!cloned_property_result.is_error()) {
@ -398,12 +398,12 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo
});
// 9. Wait until promise is resolved, or timer's timeout fired flag is set, whichever occurs first.
auto reaction_steps = JS::create_heap_function(vm.heap(), [&realm, promise, timer, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
auto reaction_steps = JS::create_heap_function(vm.heap(), [&realm, &browsing_context, promise, timer, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
if (timer->is_timed_out())
return JS::js_undefined();
timer->stop();
auto json_value_or_error = json_clone(realm, promise->result());
auto json_value_or_error = json_clone(realm, browsing_context, promise->result());
if (json_value_or_error.is_error()) {
auto error_object = JsonObject {};
error_object.set("name", "Error");
@ -513,12 +513,12 @@ void execute_async_script(HTML::BrowsingContext const& browsing_context, ByteStr
});
// 9. Wait until promise is resolved, or timer's timeout fired flag is set, whichever occurs first.
auto reaction_steps = JS::create_heap_function(vm.heap(), [&realm, promise, timer, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
auto reaction_steps = JS::create_heap_function(vm.heap(), [&realm, &browsing_context, promise, timer, on_complete](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
if (timer->is_timed_out())
return JS::js_undefined();
timer->stop();
auto json_value_or_error = json_clone(realm, promise->result());
auto json_value_or_error = json_clone(realm, browsing_context, promise->result());
if (json_value_or_error.is_error()) {
auto error_object = JsonObject {};
error_object.set("name", "Error");

View file

@ -565,7 +565,7 @@ Messages::WebDriverClient::SwitchToFrameResponse WebDriverConnection::switch_to_
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_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. If element is not a frame or iframe element, return error with error code no such frame.
bool is_frame = is<Web::HTML::HTMLFrameElement>(*element);
@ -902,7 +902,7 @@ Messages::WebDriverClient::FindElementFromElementResponse WebDriverConnection::f
auto start_node_getter = [&]() -> StartNodeGetter::ReturnType {
// 7. Let start node be the result of trying to get a known connected element with url variable element id.
return TRY(Web::WebDriver::get_known_element(element_id));
return TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
};
// 8. Let result be the value of trying to Find with start node, location strategy, and selector.
@ -938,7 +938,7 @@ Messages::WebDriverClient::FindElementsFromElementResponse WebDriverConnection::
auto start_node_getter = [&]() -> StartNodeGetter::ReturnType {
// 7. Let start node be the result of trying to get a known connected element with url variable element id.
return TRY(Web::WebDriver::get_known_element(element_id));
return TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
};
// 8. Return the result of trying to Find with start node, location strategy, and selector.
@ -1041,7 +1041,7 @@ Messages::WebDriverClient::GetElementShadowRootResponse WebDriverConnection::get
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let shadow root be element's shadow root.
auto shadow_root = element->shadow_root();
@ -1067,7 +1067,7 @@ Messages::WebDriverClient::IsElementSelectedResponse WebDriverConnection::is_ele
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let selected be the value corresponding to the first matching statement:
bool selected = false;
@ -1103,7 +1103,7 @@ Messages::WebDriverClient::GetElementAttributeResponse WebDriverConnection::get_
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let result be the result of the first matching condition:
Optional<ByteString> result;
@ -1137,7 +1137,7 @@ Messages::WebDriverClient::GetElementPropertyResponse WebDriverConnection::get_e
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
Optional<ByteString> result;
@ -1170,7 +1170,7 @@ Messages::WebDriverClient::GetElementCssValueResponse WebDriverConnection::get_e
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let computed value be the result of the first matching condition:
ByteString computed_value;
@ -1203,7 +1203,7 @@ Messages::WebDriverClient::GetElementTextResponse WebDriverConnection::get_eleme
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let rendered text be the result of performing implementation-specific steps whose result is exactly the same as the result of a Function.[[Call]](null, element) with bot.dom.getVisibleText as the this value.
auto rendered_text = element->text_content();
@ -1222,7 +1222,7 @@ Messages::WebDriverClient::GetElementTagNameResponse WebDriverConnection::get_el
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let qualified name be the result of getting elements tagName IDL attribute.
auto qualified_name = element->tag_name();
@ -1241,7 +1241,7 @@ Messages::WebDriverClient::GetElementRectResponse WebDriverConnection::get_eleme
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Calculate the absolute position of element and let it be coordinates.
// 5. Let rect be elements bounding rectangle.
@ -1272,7 +1272,7 @@ Messages::WebDriverClient::IsElementEnabledResponse WebDriverConnection::is_elem
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let enabled be a boolean initially set to true if the current browsing contexts active documents type is not "xml".
// 5. Otherwise, let enabled to false and jump to the last step of this algorithm.
@ -1298,7 +1298,7 @@ Messages::WebDriverClient::GetComputedRoleResponse WebDriverConnection::get_comp
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let role be the result of computing the WAI-ARIA role of element.
auto role = element->role_or_default();
@ -1319,7 +1319,7 @@ Messages::WebDriverClient::GetComputedLabelResponse WebDriverConnection::get_com
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Let label be the result of a Accessible Name and Description Computation for the Accessible Name of the element.
auto label = element->accessible_name(element->document()).release_value_but_fixme_should_propagate_errors();
@ -1338,7 +1338,7 @@ Messages::WebDriverClient::ElementClickResponse WebDriverConnection::element_cli
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known element with element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. If the element is an input element in the file upload state return error with error code invalid argument.
if (is<Web::HTML::HTMLInputElement>(*element)) {
@ -1467,7 +1467,7 @@ Messages::WebDriverClient::ElementClickResponse WebDriverConnection::element_cli
pointer_move_action.pointer_move_fields().position = { 0, 0 };
// 10. Set a property origin to element on pointer move action.
auto origin = Web::WebDriver::get_or_create_a_web_element_reference(*element);
auto origin = Web::WebDriver::get_or_create_a_web_element_reference(current_browsing_context(), *element);
pointer_move_action.pointer_move_fields().origin = MUST(String::from_byte_string(origin));
// 11. Let pointer down action be an action object constructed with arguments input id, "pointer", and "pointerDown".
@ -1561,7 +1561,7 @@ Messages::WebDriverClient::ElementClearResponse WebDriverConnection::element_cle
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known element with session and element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. If element is not editable, return an error with error code invalid element state.
if (!Web::WebDriver::is_element_editable(*element))
@ -1617,7 +1617,7 @@ Messages::WebDriverClient::ElementSendKeysResponse WebDriverConnection::element_
TRY(handle_any_user_prompts());
// 5. Let element be the result of trying to get a known element with session and URL variables[element id].
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 6. Let file be true if element is input element in the file upload state, or false otherwise.
auto file = is<Web::HTML::HTMLInputElement>(*element) && static_cast<Web::HTML::HTMLInputElement&>(*element).type_state() == Web::HTML::HTMLInputElement::TypeAttributeState::FileUpload;
@ -2273,7 +2273,7 @@ Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::ta
TRY(handle_any_user_prompts());
// 3. Let element be the result of trying to get a known connected element with url variable element id.
auto element = TRY(Web::WebDriver::get_known_element(element_id));
auto element = TRY(Web::WebDriver::get_known_element(current_browsing_context(), element_id));
// 4. Scroll into view the element.
(void)scroll_element_into_view(*element);
@ -2545,14 +2545,14 @@ ErrorOr<JsonArray, Web::WebDriver::Error> WebDriverConnection::find(StartNodeGet
// 8. For each element in elements returned, append the web element reference object for element, to result.
for (size_t i = 0; i < elements->length(); ++i)
TRY(result.append(Web::WebDriver::web_element_reference_object(*elements->item(i))));
TRY(result.append(Web::WebDriver::web_element_reference_object(current_browsing_context(), *elements->item(i))));
// 9. Return success with data result.
return result;
}
// https://w3c.github.io/webdriver/#dfn-json-deserialize
static ErrorOr<JS::Value, Web::WebDriver::Error> json_deserialize(JS::VM& vm, JsonValue const& value)
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:
@ -2570,7 +2570,7 @@ static ErrorOr<JS::Value, Web::WebDriver::Error> json_deserialize(JS::VM& vm, Js
// -> 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());
return Web::WebDriver::deserialize_web_element(browsing_context, value.as_object());
}
// FIXME: -> Object that represents a shadow root
@ -2604,7 +2604,7 @@ ErrorOr<WebDriverConnection::ScriptArguments, Web::WebDriver::Error> WebDriverCo
auto arguments = JS::MarkedVector<JS::Value> { vm.heap() };
TRY(args.try_for_each([&](auto const& arg) -> ErrorOr<void, Web::WebDriver::Error> {
arguments.append(TRY(json_deserialize(vm, arg)));
arguments.append(TRY(json_deserialize(vm, current_browsing_context(), arg)));
return {};
}));