mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 17:28:11 +00:00
WebContent+WebDriver: Move Find Element to WebContent
Note that this does nothing to "fix" how element references are created. We continue to return the element ID because, otherwise, all other element WebDriver endpoints would break. On the bright side, we avoid several IPC round trips now that we perform the entire 'find' operation in the WebContent process; and we are able to work directly on DOM nodes.
This commit is contained in:
parent
15916e5c14
commit
61de50c7fd
6 changed files with 120 additions and 58 deletions
|
@ -50,6 +50,51 @@ static Gfx::IntRect compute_window_rect(Web::Page const& page)
|
|||
};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-get-or-create-a-web-element-reference
|
||||
static String get_or_create_a_web_element_reference(Web::DOM::Node const& element)
|
||||
{
|
||||
// FIXME: 1. For each known element of the current browsing context’s list of known elements:
|
||||
// FIXME: 1. If known element equals element, return success with known element’s web element reference.
|
||||
// FIXME: 2. Add element to the list of known elements of the current browsing context.
|
||||
// FIXME: 3. Return success with the element’s web element reference.
|
||||
|
||||
return String::number(element.id());
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-web-element-reference-object
|
||||
static JsonObject web_element_reference_object(Web::DOM::Node const& element)
|
||||
{
|
||||
// https://w3c.github.io/webdriver/#dfn-web-element-identifier
|
||||
static String const web_element_identifier = "element-6066-11e4-a52e-4f735466cecf"sv;
|
||||
|
||||
// 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);
|
||||
|
||||
// 3. Return a JSON Object initialized with a property with name identifier and value reference.
|
||||
JsonObject object;
|
||||
object.set("name"sv, identifier);
|
||||
object.set("value"sv, reference);
|
||||
return object;
|
||||
}
|
||||
|
||||
static ErrorOr<String, Web::WebDriver::Error> get_property(JsonValue const& payload, StringView key)
|
||||
{
|
||||
if (!payload.is_object())
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload is not a JSON object");
|
||||
|
||||
auto const* property = payload.as_object().get_ptr(key);
|
||||
|
||||
if (!property)
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("No property called '{}' present", key));
|
||||
if (!property->is_string())
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Property '{}' is not a String", key));
|
||||
|
||||
return property->as_string();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebDriverConnection>> WebDriverConnection::connect(ConnectionFromClient& web_content_client, PageHost& page_host, String const& webdriver_ipc_path)
|
||||
{
|
||||
dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_ipc_path);
|
||||
|
@ -261,6 +306,43 @@ Messages::WebDriverClient::MinimizeWindowResponse WebDriverConnection::minimize_
|
|||
return serialize_rect(window_rect);
|
||||
}
|
||||
|
||||
// 12.3.2 Find Element, https://w3c.github.io/webdriver/#dfn-find-element
|
||||
Messages::WebDriverClient::FindElementResponse WebDriverConnection::find_element(JsonValue const& payload)
|
||||
{
|
||||
// 1. Let location strategy be the result of getting a property called "using".
|
||||
auto location_strategy_string = TRY(get_property(payload, "using"sv));
|
||||
auto location_strategy = Web::WebDriver::location_strategy_from_string(location_strategy_string);
|
||||
|
||||
// 2. If location strategy is not present as a keyword in the table of location strategies, return error with error code invalid argument.
|
||||
if (!location_strategy.has_value())
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, String::formatted("Location strategy '{}' is invalid", location_strategy_string));
|
||||
|
||||
// 3. Let selector be the result of getting a property called "value".
|
||||
// 4. If selector is undefined, return error with error code invalid argument.
|
||||
auto selector = TRY(get_property(payload, "value"sv));
|
||||
|
||||
// 5. If the current browsing context is no longer open, return error with error code no such window.
|
||||
TRY(ensure_open_top_level_browsing_context());
|
||||
|
||||
// FIXME: 6. Handle any user prompts and return its value if it is an error.
|
||||
|
||||
// 7. Let start node be the current browsing context’s document element.
|
||||
auto* start_node = m_page_host.page().top_level_browsing_context().active_document();
|
||||
|
||||
// 8. If start node is null, return error with error code no such element.
|
||||
if (!start_node)
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchElement, "document element does not exist"sv);
|
||||
|
||||
// 9. Let result be the result of trying to Find with start node, location strategy, and selector.
|
||||
auto result = TRY(find(*start_node, *location_strategy, selector));
|
||||
|
||||
// 10. If result is empty, return error with error code no such element. Otherwise, return the first element of result.
|
||||
if (result.is_empty())
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchElement, "The requested element does not exist"sv);
|
||||
|
||||
return make_success_response(result.at(0));
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-no-longer-open
|
||||
ErrorOr<void, Web::WebDriver::Error> WebDriverConnection::ensure_open_top_level_browsing_context()
|
||||
{
|
||||
|
@ -310,4 +392,36 @@ Gfx::IntRect WebDriverConnection::iconify_the_window()
|
|||
return rect;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-find
|
||||
ErrorOr<JsonArray, Web::WebDriver::Error> WebDriverConnection::find(Web::DOM::ParentNode& start_node, Web::WebDriver::LocationStrategy using_, StringView value)
|
||||
{
|
||||
// FIXME: 1. Let end time be the current time plus the session implicit wait timeout.
|
||||
|
||||
// 2. Let location strategy be equal to using.
|
||||
auto location_strategy = using_;
|
||||
|
||||
// 3. Let selector be equal to value.
|
||||
auto selector = value;
|
||||
|
||||
// 4. Let elements returned be the result of trying to call the relevant element location strategy with arguments start node, and selector.
|
||||
auto elements = Web::WebDriver::invoke_location_strategy(location_strategy, start_node, selector);
|
||||
|
||||
// 5. If a DOMException, SyntaxError, XPathException, or other error occurs during the execution of the element location strategy, return error invalid selector.
|
||||
if (elements.is_error())
|
||||
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidSelector, String::formatted("The location strategy could not finish: {}", elements.error().message));
|
||||
|
||||
// FIXME: 6. If elements returned is empty and the current time is less than end time return to step 4. Otherwise, continue to the next step.
|
||||
|
||||
// 7. Let result be an empty JSON List.
|
||||
JsonArray result;
|
||||
result.ensure_capacity(elements.value()->length());
|
||||
|
||||
// 8. For each element in elements returned, append the web element reference object for element, to result.
|
||||
for (size_t i = 0; i < elements.value()->length(); ++i)
|
||||
result.append(web_element_reference_object(*elements.value()->item(i)));
|
||||
|
||||
// 9. Return success with data result.
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue