diff --git a/Userland/Applications/Browser/WebDriverSessionClient.ipc b/Userland/Applications/Browser/WebDriverSessionClient.ipc index 62c78bec39..76fc2f25ab 100644 --- a/Userland/Applications/Browser/WebDriverSessionClient.ipc +++ b/Userland/Applications/Browser/WebDriverSessionClient.ipc @@ -8,6 +8,9 @@ #include #include +// FIXME: This isn't used here, but the generated IPC fails to compile without this include. +#include + endpoint WebDriverSessionClient { quit() =| diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index a2865d4ca6..a98f3b03b2 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -3,6 +3,9 @@ #include #include +// FIXME: This isn't used here, but the generated IPC fails to compile without this include. +#include + endpoint WebContentClient { did_start_loading(URL url) =| diff --git a/Userland/Services/WebContent/WebDriverClient.ipc b/Userland/Services/WebContent/WebDriverClient.ipc index 02292f5cf4..e91a73ef6d 100644 --- a/Userland/Services/WebContent/WebDriverClient.ipc +++ b/Userland/Services/WebContent/WebDriverClient.ipc @@ -1,3 +1,6 @@ +#include + endpoint WebDriverClient { set_is_webdriver_active(bool active) =| + navigate_to(JsonValue payload) => (Web::WebDriver::Response response) } diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index 4119ca716e..898297d957 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -19,6 +19,21 @@ namespace WebContent { +#define DRIVER_TRY(expression) \ + ({ \ + auto _temporary_result = (expression); \ + if (_temporary_result.is_error()) [[unlikely]] \ + return { _temporary_result.release_error() }; \ + _temporary_result.release_value(); \ + }) + +static JsonValue make_success_response(JsonValue value) +{ + JsonObject result; + result.set("value", move(value)); + return result; +} + ErrorOr> WebDriverConnection::connect(PageHost& page_host, String const& webdriver_ipc_path) { dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_ipc_path); @@ -39,4 +54,45 @@ void WebDriverConnection::set_is_webdriver_active(bool is_webdriver_active) m_page_host.set_is_webdriver_active(is_webdriver_active); } +// 10.1 Navigate To, https://w3c.github.io/webdriver/#navigate-to +Messages::WebDriverClient::NavigateToResponse WebDriverConnection::navigate_to(JsonValue const& payload) +{ + dbgln_if(WEBDRIVER_DEBUG, "WebDriverConnection::navigate_to {}", payload); + + // 1. If the current top-level browsing context is no longer open, return error with error code no such window. + DRIVER_TRY(ensure_open_top_level_browsing_context()); + + // 2. Let url be the result of getting the property url from the parameters argument. + if (!payload.is_object() || !payload.as_object().has_string("url"sv)) + return { Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload doesn't have a string `url`"sv) }; + URL url(payload.as_object().get_ptr("url"sv)->as_string()); + + // FIXME: 3. If url is not an absolute URL or is not an absolute URL with fragment or not a local scheme, return error with error code invalid argument. + // FIXME: 4. Handle any user prompts and return its value if it is an error. + // FIXME: 5. Let current URL be the current top-level browsing context’s active document’s URL. + // FIXME: 6. If current URL and url do not have the same absolute URL: + // FIXME: a. If timer has not been started, start a timer. If this algorithm has not completed before timer reaches the session’s session page load timeout in milliseconds, return an error with error code timeout. + + // 7. Navigate the current top-level browsing context to url. + m_page_host.page().load(url); + + // FIXME: 8. If url is special except for file and current URL and URL do not have the same absolute URL: + // FIXME: a. Try to wait for navigation to complete. + // FIXME: b. Try to run the post-navigation checks. + // FIXME: 9. Set the current browsing context with the current top-level browsing context. + // 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. + + // 11. Return success with data null. + return { make_success_response({}) }; +} + +// https://w3c.github.io/webdriver/#dfn-no-longer-open +ErrorOr WebDriverConnection::ensure_open_top_level_browsing_context() +{ + // A browsing context is said to be no longer open if it has been discarded. + if (m_page_host.page().top_level_browsing_context().has_been_discarded()) + return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::NoSuchWindow, "Window not found"sv); + return {}; +} + } diff --git a/Userland/Services/WebContent/WebDriverConnection.h b/Userland/Services/WebContent/WebDriverConnection.h index 797154e5ef..ac756e2496 100644 --- a/Userland/Services/WebContent/WebDriverConnection.h +++ b/Userland/Services/WebContent/WebDriverConnection.h @@ -29,6 +29,9 @@ private: virtual void die() override { } virtual void set_is_webdriver_active(bool) override; + virtual Messages::WebDriverClient::NavigateToResponse navigate_to(JsonValue const& payload) override; + + ErrorOr ensure_open_top_level_browsing_context(); PageHost& m_page_host; }; diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index ad11fcb3bc..d62008b108 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -482,8 +482,7 @@ Web::WebDriver::Response Client::handle_navigate_to(Vector const& pa { dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session//url"); auto* session = TRY(find_session_with_id(parameters[0])); - auto result = TRY(session->navigate_to(payload)); - return make_json_value(result); + return session->web_content_connection().navigate_to(payload); } // 10.2 Get Current URL, https://w3c.github.io/webdriver/#dfn-get-current-url diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 6046a69394..10e644e58b 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -165,40 +165,6 @@ Web::WebDriver::Response Session::set_timeouts(JsonValue const& payload) return JsonValue {}; } -// 10.1 Navigate To, https://w3c.github.io/webdriver/#dfn-navigate-to -Web::WebDriver::Response Session::navigate_to(JsonValue const& payload) -{ - // 1. If the current top-level browsing context is no longer open, return error with error code no such window. - TRY(check_for_open_top_level_browsing_context_or_return_error()); - - // FIXME 2. Handle any user prompts and return its value if it is an error. - - // 3. If the url property is missing from the parameters argument or it is not a string, return error with error code invalid argument. - if (!payload.is_object() || !payload.as_object().has_string("url"sv)) { - return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, "Payload doesn't have a string url"); - } - - // 4. Let url be the result of getting a property named url from the parameters argument. - URL url(payload.as_object().get_ptr("url"sv)->as_string()); - - // FIXME: 5. If url is not an absolute URL or an absolute URL with fragment, return error with error code invalid argument. [URL] - - // 6. Let url be the result of getting a property named url from the parameters argument. - // Duplicate step? - - // 7. Navigate the current top-level browsing context to url. - m_browser_connection->async_set_url(url); - - // FIXME: 8. Run the post-navigation checks and return its value if it is an error. - - // FIXME: 9. Wait for navigation to complete and return its value if it is an error. - - // FIXME: 10. Set the current browsing context to the current top-level browsing context. - - // 11. Return success with data null. - return JsonValue(); -} - // 10.2 Get Current URL, https://w3c.github.io/webdriver/#dfn-get-current-url Web::WebDriver::Response Session::get_current_url() { diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index e7d711d7f5..baa97fd1a9 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -51,7 +51,6 @@ public: ErrorOr stop(); JsonObject get_timeouts(); Web::WebDriver::Response set_timeouts(JsonValue const& payload); - Web::WebDriver::Response navigate_to(JsonValue const& url); Web::WebDriver::Response get_current_url(); Web::WebDriver::Response back(); Web::WebDriver::Response forward();