WebContent+WebDriver: Consolidate driver execution completion callbacks

Some WebDriver hooks will need to inform the client that execution has
completed, but without any knowledge of what endpoint was running. Since
there can only ever be a single WebDriver endpoint executing at once, we
can replace the completion callbacks with a single callback.
This commit is contained in:
Timothy Flynn 2024-11-01 07:42:21 -04:00 committed by Andreas Kling
parent 1be67faab7
commit 9dc1302768
Notes: github-actions[bot] 2024-11-02 10:10:43 +00:00
7 changed files with 126 additions and 289 deletions

View file

@ -301,7 +301,7 @@ Messages::WebDriverClient::NavigateToResponse WebDriverConnection::navigate_to(J
// FIXME: 10. If the current top-level browsing context contains a refresh state pragma directive of time 1 second or less, wait until the refresh timeout has elapsed, a new navigate has begun, and return to the first step of this algorithm.
async_navigation_complete(move(result));
async_driver_execution_complete(move(result));
});
// 8. If url is special except for file and current URL and URL do not have the same absolute URL:
@ -713,7 +713,7 @@ Messages::WebDriverClient::SetWindowRectResponse WebDriverConnection::set_window
}
if (m_pending_window_rect_requests == 0)
async_window_rect_updated(serialize_rect(compute_window_rect(page)));
async_driver_execution_complete(serialize_rect(compute_window_rect(page)));
}));
// 14. Return success with data set to the WindowRect object for the current top-level browsing context.
@ -759,7 +759,7 @@ Messages::WebDriverClient::MinimizeWindowResponse WebDriverConnection::minimize_
// 5. Iconify the window.
iconify_the_window(JS::create_heap_function(current_top_level_browsing_context()->heap(), [this]() {
auto& page = current_top_level_browsing_context()->page();
async_window_rect_updated(serialize_rect(compute_window_rect(page)));
async_driver_execution_complete(serialize_rect(compute_window_rect(page)));
}));
// 6. Return success with data set to the WindowRect object for the current top-level browsing context.
@ -858,7 +858,7 @@ Messages::WebDriverClient::FindElementResponse WebDriverConnection::find_element
// 9. Let result be the result of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
// 10. If result is empty, return error with error code no such element. Otherwise, return the first element of result.
async_find_elements_complete(extract_first_element(move(result)));
async_driver_execution_complete(extract_first_element(move(result)));
}));
return JsonValue {};
@ -899,7 +899,7 @@ Messages::WebDriverClient::FindElementsResponse WebDriverConnection::find_elemen
// 9. Return the result of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
async_find_elements_complete(move(result));
async_driver_execution_complete(move(result));
}));
return JsonValue {};
@ -934,7 +934,7 @@ Messages::WebDriverClient::FindElementFromElementResponse WebDriverConnection::f
// 8. Let result be the value of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
// 9. If result is empty, return error with error code no such element. Otherwise, return the first element of result.
async_find_elements_complete(extract_first_element(move(result)));
async_driver_execution_complete(extract_first_element(move(result)));
}));
return JsonValue {};
@ -968,7 +968,7 @@ Messages::WebDriverClient::FindElementsFromElementResponse WebDriverConnection::
// 8. Return the result of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
async_find_elements_complete(move(result));
async_driver_execution_complete(move(result));
}));
return JsonValue {};
@ -1003,7 +1003,7 @@ Messages::WebDriverClient::FindElementFromShadowRootResponse WebDriverConnection
// 8. Let result be the value of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
// 9. If result is empty, return error with error code no such element. Otherwise, return the first element of result.
async_find_elements_complete(extract_first_element(move(result)));
async_driver_execution_complete(extract_first_element(move(result)));
}));
return JsonValue {};
@ -1037,7 +1037,7 @@ Messages::WebDriverClient::FindElementsFromShadowRootResponse WebDriverConnectio
// 8. Return the result of trying to Find with session, start node, location strategy, and selector.
find(*location_strategy, move(selector), get_start_node, JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
async_find_elements_complete(move(result));
async_driver_execution_complete(move(result));
}));
return JsonValue {};
@ -1408,9 +1408,9 @@ Messages::WebDriverClient::ElementClickResponse WebDriverConnection::element_cli
// FIXME: 12. Try to run the post-navigation checks.
if (navigation_result.is_error())
async_actions_performed(move(navigation_result));
async_driver_execution_complete(move(navigation_result));
else
async_actions_performed(move(result));
async_driver_execution_complete(move(result));
}));
});
@ -1730,7 +1730,7 @@ Messages::WebDriverClient::ElementSendKeysResponse WebDriverConnection::element_
// NOTE: These events are fired by `did_select_files` as an element task. So instead of firing them here, we spin
// the event loop once before informing the client that the action is complete.
Web::HTML::queue_a_task(Web::HTML::Task::Source::Unspecified, nullptr, nullptr, JS::create_heap_function(current_browsing_context().heap(), [this]() {
async_actions_performed(JsonValue {});
async_driver_execution_complete(JsonValue {});
}));
// 8. Return success with data null.
@ -1754,7 +1754,7 @@ Messages::WebDriverClient::ElementSendKeysResponse WebDriverConnection::element_
// FIXME: 4. If element is suffering from bad input return an error with error code invalid argument.
// 5. Return success with data null.
async_actions_performed(JsonValue {});
async_driver_execution_complete(JsonValue {});
return JsonValue {};
}
// -> element is content editable
@ -1810,7 +1810,7 @@ Messages::WebDriverClient::ElementSendKeysResponse WebDriverConnection::element_
// 14. Remove an input source with input state and input id.
Web::WebDriver::remove_input_source(input_state, input_id);
async_actions_performed(move(result));
async_driver_execution_complete(move(result));
}));
// 15. Return success with data null.
@ -1926,7 +1926,7 @@ void WebDriverConnection::handle_script_response(Web::WebDriver::ExecuteScriptRe
VERIFY_NOT_REACHED();
}();
async_script_executed(move(response));
async_driver_execution_complete(move(response));
}
// 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
@ -2125,7 +2125,7 @@ Messages::WebDriverClient::PerformActionsResponse WebDriverConnection::perform_a
// results in an error return that error.
auto on_complete = JS::create_heap_function(current_browsing_context().heap(), [this](Web::WebDriver::Response result) {
m_action_executor = nullptr;
async_actions_performed(move(result));
async_driver_execution_complete(move(result));
});
m_action_executor = Web::WebDriver::dispatch_actions(input_state, move(actions_by_tick), current_browsing_context(), move(actions_options), on_complete);
@ -2176,7 +2176,7 @@ Messages::WebDriverClient::DismissAlertResponse WebDriverConnection::dismiss_ale
// 3. Dismiss the current user prompt.
current_browsing_context().page().dismiss_dialog(JS::create_heap_function(current_browsing_context().heap(), [this]() {
async_dialog_closed(JsonValue {});
async_driver_execution_complete(JsonValue {});
}));
// 4. Return success with data null.
@ -2195,7 +2195,7 @@ Messages::WebDriverClient::AcceptAlertResponse WebDriverConnection::accept_alert
// 3. Accept the current user prompt.
current_browsing_context().page().accept_dialog(JS::create_heap_function(current_browsing_context().heap(), [this]() {
async_dialog_closed(JsonValue {});
async_driver_execution_complete(JsonValue {});
}));
// 4. Return success with data null.
@ -2279,7 +2279,7 @@ Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_scre
// b. Let screenshot result be the result of trying to call draw a bounding box from the framebuffer, given root rect as an argument.
auto screenshot_result = Web::WebDriver::draw_bounding_box_from_the_framebuffer(*current_top_level_browsing_context(), *document->document_element(), root_rect);
if (screenshot_result.is_error()) {
async_screenshot_taken(screenshot_result.release_error());
async_driver_execution_complete(screenshot_result.release_error());
return;
}
@ -2291,7 +2291,7 @@ Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_scre
auto encoded_string = Web::WebDriver::encode_canvas_element(canvas);
// 3. Return success with data encoded string.
async_screenshot_taken(move(encoded_string));
async_driver_execution_complete(move(encoded_string));
}));
return JsonValue {};
@ -2323,7 +2323,7 @@ Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::ta
// b. Let screenshot result be the result of trying to call draw a bounding box from the framebuffer, given element rect as an argument.
auto screenshot_result = Web::WebDriver::draw_bounding_box_from_the_framebuffer(current_browsing_context(), element, element_rect);
if (screenshot_result.is_error()) {
async_screenshot_taken(screenshot_result.release_error());
async_driver_execution_complete(screenshot_result.release_error());
return;
}
@ -2335,7 +2335,7 @@ Messages::WebDriverClient::TakeElementScreenshotResponse WebDriverConnection::ta
auto encoded_string = Web::WebDriver::encode_canvas_element(canvas);
// 6. Return success with data encoded string.
async_screenshot_taken(move(encoded_string));
async_driver_execution_complete(move(encoded_string));
}));
return JsonValue {};
@ -2377,7 +2377,7 @@ void WebDriverConnection::set_current_top_level_browsing_context(Web::HTML::Brow
if (m_current_top_level_browsing_context) {
m_current_top_level_browsing_context->page().set_window_rect_observer(JS::create_heap_function(m_current_top_level_browsing_context->heap(), [this](Web::DevicePixelRect rect) {
if (m_pending_window_rect_requests > 0 && --m_pending_window_rect_requests == 0)
async_window_rect_updated(serialize_rect(rect.to_type<int>()));
async_driver_execution_complete(serialize_rect(rect.to_type<int>()));
}));
}
@ -2553,7 +2553,7 @@ void WebDriverConnection::page_did_open_dialog(Badge<PageClient>)
// [[Value]]: null, [[Target]]: empty }, but continue to run the other steps of this algorithm in parallel.
if (m_has_pending_script_execution) {
m_has_pending_script_execution = false;
async_script_executed(JsonValue {});
async_driver_execution_complete(JsonValue {});
}
}

View file

@ -1,11 +1,5 @@
#include <LibWeb/WebDriver/Response.h>
endpoint WebDriverServer {
navigation_complete(Web::WebDriver::Response response) =|
window_rect_updated(Web::WebDriver::Response response) =|
find_elements_complete(Web::WebDriver::Response response) =|
script_executed(Web::WebDriver::Response response) =|
actions_performed(Web::WebDriver::Response response) =|
dialog_closed(Web::WebDriver::Response response) =|
screenshot_taken(Web::WebDriver::Response response) =|
driver_execution_complete(Web::WebDriver::Response response) =|
}

View file

@ -241,7 +241,10 @@ Web::WebDriver::Response Client::navigate_to(Web::WebDriver::Parameters paramete
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/url");
auto session = TRY(find_session_with_id(parameters[0]));
return session->navigate_to(payload);
return session->perform_async_action([&](auto& connection) {
return connection.navigate_to(move(payload));
});
}
// 10.2 Get Current URL, https://w3c.github.io/webdriver/#dfn-get-current-url
@ -397,7 +400,10 @@ Web::WebDriver::Response Client::set_window_rect(Web::WebDriver::Parameters para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/rect");
auto session = TRY(find_session_with_id(parameters[0]));
return session->set_window_rect(payload);
return session->perform_async_action([&](auto& connection) {
return connection.set_window_rect(move(payload));
});
}
// 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window
@ -406,7 +412,10 @@ Web::WebDriver::Response Client::maximize_window(Web::WebDriver::Parameters para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/maximize");
auto session = TRY(find_session_with_id(parameters[0]));
return session->maximize_window();
return session->perform_async_action([&](auto& connection) {
return connection.maximize_window();
});
}
// 11.8.4 Minimize Window, https://w3c.github.io/webdriver/#minimize-window
@ -415,7 +424,10 @@ Web::WebDriver::Response Client::minimize_window(Web::WebDriver::Parameters para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/minimize");
auto session = TRY(find_session_with_id(parameters[0]));
return session->minimize_window();
return session->perform_async_action([&](auto& connection) {
return connection.minimize_window();
});
}
// 11.8.5 Fullscreen Window, https://w3c.github.io/webdriver/#dfn-fullscreen-window
@ -424,7 +436,10 @@ Web::WebDriver::Response Client::fullscreen_window(Web::WebDriver::Parameters pa
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/window/fullscreen");
auto session = TRY(find_session_with_id(parameters[0]));
return session->fullscreen_window();
return session->perform_async_action([&](auto& connection) {
return connection.fullscreen_window();
});
}
// Extension: Consume User Activation, https://html.spec.whatwg.org/multipage/interaction.html#user-activation-user-agent-automation
@ -442,7 +457,10 @@ Web::WebDriver::Response Client::find_element(Web::WebDriver::Parameters paramet
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_element(payload);
return session->perform_async_action([&](auto& connection) {
return connection.find_element(move(payload));
});
}
// 12.3.3 Find Elements, https://w3c.github.io/webdriver/#dfn-find-elements
@ -451,7 +469,10 @@ Web::WebDriver::Response Client::find_elements(Web::WebDriver::Parameters parame
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/elements");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_elements(payload);
return session->perform_async_action([&](auto& connection) {
return connection.find_elements(move(payload));
});
}
// 12.3.4 Find Element From Element, https://w3c.github.io/webdriver/#dfn-find-element-from-element
@ -460,7 +481,10 @@ Web::WebDriver::Response Client::find_element_from_element(Web::WebDriver::Param
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/element");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_element_from_element(move(parameters[1]), move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.find_element_from_element(move(payload), move(parameters[1]));
});
}
// 12.3.5 Find Elements From Element, https://w3c.github.io/webdriver/#dfn-find-elements-from-element
@ -469,7 +493,10 @@ Web::WebDriver::Response Client::find_elements_from_element(Web::WebDriver::Para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/elements");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_elements_from_element(move(parameters[1]), move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.find_elements_from_element(move(payload), move(parameters[1]));
});
}
// 12.3.6 Find Element From Shadow Root, https://w3c.github.io/webdriver/#find-element-from-shadow-root
@ -478,7 +505,10 @@ Web::WebDriver::Response Client::find_element_from_shadow_root(Web::WebDriver::P
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/shadow/<shadow_id>/element");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_element_from_shadow_root(move(parameters[1]), move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.find_element_from_shadow_root(move(payload), move(parameters[1]));
});
}
// 12.3.7 Find Elements From Shadow Root, https://w3c.github.io/webdriver/#find-elements-from-shadow-root
@ -487,7 +517,10 @@ Web::WebDriver::Response Client::find_elements_from_shadow_root(Web::WebDriver::
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/shadow/<shadow_id>/elements");
auto session = TRY(find_session_with_id(parameters[0]));
return session->find_elements_from_shadow_root(move(parameters[1]), move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.find_elements_from_shadow_root(move(payload), move(parameters[1]));
});
}
// 12.3.8 Get Active Element, https://w3c.github.io/webdriver/#get-active-element
@ -604,7 +637,10 @@ Web::WebDriver::Response Client::element_click(Web::WebDriver::Parameters parame
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/click");
auto session = TRY(find_session_with_id(parameters[0]));
return session->element_click(move(parameters[1]));
return session->perform_async_action([&](auto& connection) {
return connection.element_click(move(parameters[1]));
});
}
// 12.5.2 Element Clear, https://w3c.github.io/webdriver/#dfn-element-clear
@ -622,7 +658,10 @@ Web::WebDriver::Response Client::element_send_keys(Web::WebDriver::Parameters pa
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/element/<element_id>/value");
auto session = TRY(find_session_with_id(parameters[0]));
return session->element_send_keys(move(parameters[1]), move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.element_send_keys(move(parameters[1]), move(payload));
});
}
// 13.1 Get Page Source, https://w3c.github.io/webdriver/#dfn-get-page-source
@ -640,7 +679,10 @@ Web::WebDriver::Response Client::execute_script(Web::WebDriver::Parameters param
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/execute/sync");
auto session = TRY(find_session_with_id(parameters[0]));
return session->execute_script(move(payload), Session::ScriptMode::Sync);
return session->perform_async_action([&](auto& connection) {
return connection.execute_script(move(payload));
});
}
// 13.2.2 Execute Async Script, https://w3c.github.io/webdriver/#dfn-execute-async-script
@ -649,7 +691,10 @@ Web::WebDriver::Response Client::execute_async_script(Web::WebDriver::Parameters
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/execute/async");
auto session = TRY(find_session_with_id(parameters[0]));
return session->execute_script(move(payload), Session::ScriptMode::Async);
return session->perform_async_action([&](auto& connection) {
return connection.execute_async_script(move(payload));
});
}
// 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
@ -703,7 +748,10 @@ Web::WebDriver::Response Client::perform_actions(Web::WebDriver::Parameters para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/actions");
auto session = TRY(find_session_with_id(parameters[0]));
return session->perform_actions(move(payload));
return session->perform_async_action([&](auto& connection) {
return connection.perform_actions(move(payload));
});
}
// 15.8 Release Actions, https://w3c.github.io/webdriver/#release-actions
@ -721,7 +769,10 @@ Web::WebDriver::Response Client::dismiss_alert(Web::WebDriver::Parameters parame
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/alert/dismiss");
auto session = TRY(find_session_with_id(parameters[0]));
return session->dismiss_alert();
return session->perform_async_action([&](auto& connection) {
return connection.dismiss_alert();
});
}
// 16.2 Accept Alert, https://w3c.github.io/webdriver/#accept-alert
@ -730,7 +781,10 @@ Web::WebDriver::Response Client::accept_alert(Web::WebDriver::Parameters paramet
{
dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/alert/accept");
auto session = TRY(find_session_with_id(parameters[0]));
return session->accept_alert();
return session->perform_async_action([&](auto& connection) {
return connection.accept_alert();
});
}
// 16.3 Get Alert Text, https://w3c.github.io/webdriver/#get-alert-text
@ -757,7 +811,10 @@ Web::WebDriver::Response Client::take_screenshot(Web::WebDriver::Parameters para
{
dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/screenshot");
auto session = TRY(find_session_with_id(parameters[0]));
return session->take_screenshot();
return session->perform_async_action([&](auto& connection) {
return connection.take_screenshot();
});
}
// 17.2 Take Element Screenshot, https://w3c.github.io/webdriver/#dfn-take-element-screenshot
@ -766,7 +823,10 @@ Web::WebDriver::Response Client::take_element_screenshot(Web::WebDriver::Paramet
{
dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/element/<element_id>/screenshot");
auto session = TRY(find_session_with_id(parameters[0]));
return session->take_element_screenshot(move(parameters[1]));
return session->perform_async_action([&](auto& connection) {
return connection.take_element_screenshot(move(parameters[1]));
});
}
// 18.1 Print Page, https://w3c.github.io/webdriver/#dfn-print-page

View file

@ -11,8 +11,7 @@
#include "Session.h"
#include "Client.h"
#include <AK/JsonObject.h>
#include <AK/ScopeGuard.h>
#include <LibCore/EventLoop.h>
#include <AK/JsonValue.h>
#include <LibCore/LocalServer.h>
#include <LibCore/StandardPaths.h>
#include <LibCore/System.h>
@ -185,160 +184,4 @@ ErrorOr<void, Web::WebDriver::Error> Session::ensure_current_window_handle_is_va
return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchWindow, "Window not found"sv);
}
template<typename Handler, typename Action>
static Web::WebDriver::Response perform_async_action(Handler& handler, Action&& action)
{
Optional<Web::WebDriver::Response> response;
ScopeGuard guard { [&]() { handler = nullptr; } };
handler = [&](auto result) { response = move(result); };
TRY(action());
Core::EventLoop::current().spin_until([&]() {
return response.has_value();
});
return response.release_value();
}
Web::WebDriver::Response Session::navigate_to(JsonValue payload) const
{
return perform_async_action(web_content_connection().on_navigation_complete, [&]() {
return web_content_connection().navigate_to(move(payload));
});
}
Web::WebDriver::Response Session::set_window_rect(JsonValue payload) const
{
return perform_async_action(web_content_connection().on_window_rect_updated, [&]() {
return web_content_connection().set_window_rect(move(payload));
});
}
Web::WebDriver::Response Session::maximize_window() const
{
return perform_async_action(web_content_connection().on_window_rect_updated, [&]() {
return web_content_connection().maximize_window();
});
}
Web::WebDriver::Response Session::minimize_window() const
{
return perform_async_action(web_content_connection().on_window_rect_updated, [&]() {
return web_content_connection().minimize_window();
});
}
Web::WebDriver::Response Session::fullscreen_window() const
{
return perform_async_action(web_content_connection().on_window_rect_updated, [&]() {
return web_content_connection().fullscreen_window();
});
}
Web::WebDriver::Response Session::find_element(JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_element(move(payload));
});
}
Web::WebDriver::Response Session::find_elements(JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_elements(move(payload));
});
}
Web::WebDriver::Response Session::find_element_from_element(String element_id, JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_element_from_element(move(payload), move(element_id));
});
}
Web::WebDriver::Response Session::find_elements_from_element(String element_id, JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_elements_from_element(move(payload), move(element_id));
});
}
Web::WebDriver::Response Session::find_element_from_shadow_root(String shadow_id, JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_element_from_shadow_root(move(payload), move(shadow_id));
});
}
Web::WebDriver::Response Session::find_elements_from_shadow_root(String shadow_id, JsonValue payload) const
{
return perform_async_action(web_content_connection().on_find_elements_complete, [&]() {
return web_content_connection().find_elements_from_shadow_root(move(payload), move(shadow_id));
});
}
Web::WebDriver::Response Session::execute_script(JsonValue payload, ScriptMode mode) const
{
return perform_async_action(web_content_connection().on_script_executed, [&]() {
switch (mode) {
case ScriptMode::Sync:
return web_content_connection().execute_script(move(payload));
case ScriptMode::Async:
return web_content_connection().execute_async_script(move(payload));
}
VERIFY_NOT_REACHED();
});
}
Web::WebDriver::Response Session::element_click(String element_id) const
{
return perform_async_action(web_content_connection().on_actions_performed, [&]() {
return web_content_connection().element_click(move(element_id));
});
}
Web::WebDriver::Response Session::element_send_keys(String element_id, JsonValue payload) const
{
return perform_async_action(web_content_connection().on_actions_performed, [&]() {
return web_content_connection().element_send_keys(move(element_id), move(payload));
});
}
Web::WebDriver::Response Session::perform_actions(JsonValue payload) const
{
return perform_async_action(web_content_connection().on_actions_performed, [&]() {
return web_content_connection().perform_actions(move(payload));
});
}
Web::WebDriver::Response Session::dismiss_alert() const
{
return perform_async_action(web_content_connection().on_dialog_closed, [&]() {
return web_content_connection().dismiss_alert();
});
}
Web::WebDriver::Response Session::accept_alert() const
{
return perform_async_action(web_content_connection().on_dialog_closed, [&]() {
return web_content_connection().accept_alert();
});
}
Web::WebDriver::Response Session::take_screenshot() const
{
return perform_async_action(web_content_connection().on_screenshot_taken, [&]() {
return web_content_connection().take_screenshot();
});
}
Web::WebDriver::Response Session::take_element_screenshot(String element_id) const
{
return perform_async_action(web_content_connection().on_screenshot_taken, [&]() {
return web_content_connection().take_element_screenshot(move(element_id));
});
}
}

View file

@ -9,12 +9,12 @@
#pragma once
#include <AK/Error.h>
#include <AK/JsonValue.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/ScopeGuard.h>
#include <AK/String.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Promise.h>
#include <LibWeb/WebDriver/Capabilities.h>
#include <LibWeb/WebDriver/Error.h>
#include <LibWeb/WebDriver/Response.h>
#include <WebDriver/WebContentConnection.h>
@ -57,35 +57,23 @@ public:
Web::WebDriver::Response get_window_handles() const;
ErrorOr<void, Web::WebDriver::Error> ensure_current_window_handle_is_valid() const;
Web::WebDriver::Response navigate_to(JsonValue) const;
template<typename Action>
Web::WebDriver::Response perform_async_action(Action&& action)
{
Optional<Web::WebDriver::Response> response;
auto& connection = web_content_connection();
enum class ScriptMode {
Sync,
Async,
};
Web::WebDriver::Response execute_script(JsonValue, ScriptMode) const;
ScopeGuard guard { [&]() { connection.on_driver_execution_complete = nullptr; } };
connection.on_driver_execution_complete = [&](auto result) { response = move(result); };
Web::WebDriver::Response set_window_rect(JsonValue) const;
Web::WebDriver::Response maximize_window() const;
Web::WebDriver::Response minimize_window() const;
Web::WebDriver::Response fullscreen_window() const;
TRY(action(connection));
Web::WebDriver::Response find_element(JsonValue) const;
Web::WebDriver::Response find_elements(JsonValue) const;
Web::WebDriver::Response find_element_from_element(String, JsonValue) const;
Web::WebDriver::Response find_elements_from_element(String, JsonValue) const;
Web::WebDriver::Response find_element_from_shadow_root(String, JsonValue) const;
Web::WebDriver::Response find_elements_from_shadow_root(String, JsonValue) const;
Core::EventLoop::current().spin_until([&]() {
return response.has_value();
});
Web::WebDriver::Response element_click(String) const;
Web::WebDriver::Response element_send_keys(String, JsonValue) const;
Web::WebDriver::Response perform_actions(JsonValue) const;
Web::WebDriver::Response dismiss_alert() const;
Web::WebDriver::Response accept_alert() const;
Web::WebDriver::Response take_screenshot() const;
Web::WebDriver::Response take_element_screenshot(String) const;
return response.release_value();
}
private:
using ServerPromise = Core::Promise<ErrorOr<void>>;

View file

@ -20,46 +20,10 @@ void WebContentConnection::die()
on_close();
}
void WebContentConnection::navigation_complete(Web::WebDriver::Response const& response)
void WebContentConnection::driver_execution_complete(Web::WebDriver::Response const& response)
{
if (on_navigation_complete)
on_navigation_complete(response);
}
void WebContentConnection::window_rect_updated(Web::WebDriver::Response const& response)
{
if (on_window_rect_updated)
on_window_rect_updated(response);
}
void WebContentConnection::find_elements_complete(Web::WebDriver::Response const& response)
{
if (on_find_elements_complete)
on_find_elements_complete(response);
}
void WebContentConnection::script_executed(Web::WebDriver::Response const& response)
{
if (on_script_executed)
on_script_executed(response);
}
void WebContentConnection::actions_performed(Web::WebDriver::Response const& response)
{
if (on_actions_performed)
on_actions_performed(response);
}
void WebContentConnection::dialog_closed(Web::WebDriver::Response const& response)
{
if (on_dialog_closed)
on_dialog_closed(response);
}
void WebContentConnection::screenshot_taken(Web::WebDriver::Response const& response)
{
if (on_screenshot_taken)
on_screenshot_taken(response);
if (on_driver_execution_complete)
on_driver_execution_complete(response);
}
}

View file

@ -22,24 +22,12 @@ public:
explicit WebContentConnection(IPC::Transport transport);
Function<void()> on_close;
Function<void(Web::WebDriver::Response)> on_navigation_complete;
Function<void(Web::WebDriver::Response)> on_window_rect_updated;
Function<void(Web::WebDriver::Response)> on_find_elements_complete;
Function<void(Web::WebDriver::Response)> on_script_executed;
Function<void(Web::WebDriver::Response)> on_actions_performed;
Function<void(Web::WebDriver::Response)> on_dialog_closed;
Function<void(Web::WebDriver::Response)> on_screenshot_taken;
Function<void(Web::WebDriver::Response)> on_driver_execution_complete;
private:
virtual void die() override;
virtual void navigation_complete(Web::WebDriver::Response const&) override;
virtual void window_rect_updated(Web::WebDriver::Response const&) override;
virtual void find_elements_complete(Web::WebDriver::Response const&) override;
virtual void script_executed(Web::WebDriver::Response const&) override;
virtual void actions_performed(Web::WebDriver::Response const&) override;
virtual void dialog_closed(Web::WebDriver::Response const&) override;
virtual void screenshot_taken(Web::WebDriver::Response const&) override;
virtual void driver_execution_complete(Web::WebDriver::Response const&) override;
};
}