From 9dc130276877a6da42a058cdb03002b0fa27a66a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 1 Nov 2024 07:42:21 -0400 Subject: [PATCH] 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. --- .../WebContent/WebDriverConnection.cpp | 48 +++--- .../Services/WebContent/WebDriverServer.ipc | 8 +- Userland/Services/WebDriver/Client.cpp | 100 ++++++++--- Userland/Services/WebDriver/Session.cpp | 159 +----------------- Userland/Services/WebDriver/Session.h | 42 ++--- .../WebDriver/WebContentConnection.cpp | 42 +---- .../Services/WebDriver/WebContentConnection.h | 16 +- 7 files changed, 126 insertions(+), 289 deletions(-) diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index c66fc4a6253..e838476adbc 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -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())); + async_driver_execution_complete(serialize_rect(rect.to_type())); })); } @@ -2553,7 +2553,7 @@ void WebDriverConnection::page_did_open_dialog(Badge) // [[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 {}); } } diff --git a/Userland/Services/WebContent/WebDriverServer.ipc b/Userland/Services/WebContent/WebDriverServer.ipc index 53404b22add..b1293f5340f 100644 --- a/Userland/Services/WebContent/WebDriverServer.ipc +++ b/Userland/Services/WebContent/WebDriverServer.ipc @@ -1,11 +1,5 @@ #include 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) =| } diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index 995c54e8b21..545d97c625a 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -241,7 +241,10 @@ Web::WebDriver::Response Client::navigate_to(Web::WebDriver::Parameters paramete { dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session//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//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//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//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//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//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//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//element//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//element//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//shadow//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//shadow//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//element//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//element//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//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//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//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//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//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//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//element//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 diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 39c5a10c513..21de3302476 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -11,8 +11,7 @@ #include "Session.h" #include "Client.h" #include -#include -#include +#include #include #include #include @@ -185,160 +184,4 @@ ErrorOr Session::ensure_current_window_handle_is_va return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchWindow, "Window not found"sv); } -template -static Web::WebDriver::Response perform_async_action(Handler& handler, Action&& action) -{ - Optional 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)); - }); -} - } diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 8f784be8380..c0b00d80f64 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -9,12 +9,12 @@ #pragma once #include -#include #include #include +#include #include +#include #include -#include #include #include #include @@ -57,35 +57,23 @@ public: Web::WebDriver::Response get_window_handles() const; ErrorOr ensure_current_window_handle_is_valid() const; - Web::WebDriver::Response navigate_to(JsonValue) const; + template + Web::WebDriver::Response perform_async_action(Action&& action) + { + Optional 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>; diff --git a/Userland/Services/WebDriver/WebContentConnection.cpp b/Userland/Services/WebDriver/WebContentConnection.cpp index 99e3316057b..a306399e70c 100644 --- a/Userland/Services/WebDriver/WebContentConnection.cpp +++ b/Userland/Services/WebDriver/WebContentConnection.cpp @@ -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); } } diff --git a/Userland/Services/WebDriver/WebContentConnection.h b/Userland/Services/WebDriver/WebContentConnection.h index 893c211d13d..7b2f7cf5d84 100644 --- a/Userland/Services/WebDriver/WebContentConnection.h +++ b/Userland/Services/WebDriver/WebContentConnection.h @@ -22,24 +22,12 @@ public: explicit WebContentConnection(IPC::Transport transport); Function on_close; - Function on_navigation_complete; - Function on_window_rect_updated; - Function on_find_elements_complete; - Function on_script_executed; - Function on_actions_performed; - Function on_dialog_closed; - Function on_screenshot_taken; + Function 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; }; }