From 4a6d0e0f9035ac39e7b5b5a4d126ff1c40138a7d Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 14 Sep 2024 08:04:15 -0400 Subject: [PATCH] LibWeb+WebContent: Use the current window to execute WebDriver scripts Rather than using the page's top-level window, we must use the window that is currently active in the WebDriver session. --- .../LibWeb/WebDriver/ExecuteScript.cpp | 31 +++++++++---------- .../LibWeb/WebDriver/ExecuteScript.h | 4 +-- .../WebContent/WebDriverConnection.cpp | 4 +-- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index 18ee357b5d5..502a008eac8 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -222,13 +222,12 @@ static ErrorOr clone_an_object(JS::Realm& re } // https://w3c.github.io/webdriver/#dfn-execute-a-function-body -static JS::ThrowCompletionOr execute_a_function_body(Web::Page& page, ByteString const& body, JS::MarkedVector parameters) +static JS::ThrowCompletionOr execute_a_function_body(HTML::BrowsingContext const& browsing_context, ByteString const& body, JS::MarkedVector parameters) { // FIXME: If at any point during the algorithm a user prompt appears, immediately return Completion { [[Type]]: normal, [[Value]]: null, [[Target]]: empty }, but continue to run the other steps of this algorithm in parallel. // 1. Let window be the associated window of the current browsing context’s active document. - // FIXME: This will need adjusting when WebDriver supports frames. - auto window = page.top_level_browsing_context().active_document()->window(); + auto window = browsing_context.active_document()->window(); // 2. Let environment settings be the environment settings object for window. auto& environment_settings = Web::HTML::relevant_settings_object(*window); @@ -339,12 +338,11 @@ private: JS_DEFINE_ALLOCATOR(HeapTimer); -void execute_script(Web::Page& page, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete) +void execute_script(HTML::BrowsingContext const& browsing_context, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete) { - auto* document = page.top_level_browsing_context().active_document(); - auto* window = page.top_level_browsing_context().active_window(); - auto& realm = window->realm(); - auto& vm = window->vm(); + auto const* document = browsing_context.active_document(); + auto& realm = document->realm(); + auto& vm = document->vm(); // 5. Let timer be a new timer. auto timer = vm.heap().allocate(realm); @@ -363,11 +361,11 @@ void execute_script(Web::Page& page, ByteString body, JS::MarkedVector(*promise_capability->promise()) }; // 8. Run the following substeps in parallel: - Platform::EventLoopPlugin::the().deferred_invoke([&realm, &page, promise_capability, document, promise, body = move(body), arguments = move(arguments)]() mutable { + Platform::EventLoopPlugin::the().deferred_invoke([&realm, &browsing_context, promise_capability, document, promise, body = move(body), arguments = move(arguments)]() mutable { HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object() }; // 1. Let scriptPromise be the result of promise-calling execute a function body, with arguments body and arguments. - auto script_result = execute_a_function_body(page, body, move(arguments)); + auto script_result = execute_a_function_body(browsing_context, body, move(arguments)); // 2. Upon fulfillment of scriptPromise with value v, resolve promise with value v. if (script_result.has_value()) { @@ -414,12 +412,11 @@ void execute_script(Web::Page& page, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete) +void execute_async_script(HTML::BrowsingContext const& browsing_context, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete) { - auto* document = page.top_level_browsing_context().active_document(); - auto* window = page.top_level_browsing_context().active_window(); - auto& realm = window->realm(); - auto& vm = window->vm(); + auto const* document = browsing_context.active_document(); + auto& realm = document->realm(); + auto& vm = document->vm(); // 5. Let timer be a new timer. auto timer = vm.heap().allocate(realm); @@ -438,7 +435,7 @@ void execute_async_script(Web::Page& page, ByteString body, JS::MarkedVector(*promise_capability->promise()) }; // 8. Run the following substeps in parallel: - Platform::EventLoopPlugin::the().deferred_invoke([&vm, &realm, &page, timer, document, promise_capability, promise, body = move(body), arguments = move(arguments)]() mutable { + Platform::EventLoopPlugin::the().deferred_invoke([&vm, &realm, &browsing_context, timer, document, promise_capability, promise, body = move(body), arguments = move(arguments)]() mutable { HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object() }; // 1. Let resolvingFunctions be CreateResolvingFunctions(promise). @@ -449,7 +446,7 @@ void execute_async_script(Web::Page& page, ByteString body, JS::MarkedVector 'scriptResult' (spec issue) - auto script_result = execute_a_function_body(page, body, move(arguments)); + auto script_result = execute_a_function_body(browsing_context, body, move(arguments)); // 4. If scriptResult.[[Type]] is not normal, then reject promise with value scriptResult.[[Value]], and abort these steps. // NOTE: Prior revisions of this specification did not recognize the return value of the provided script. diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.h b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.h index f14308beeb0..af7619dd015 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.h +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.h @@ -35,7 +35,7 @@ struct ExecuteScriptResultSerialized { using OnScriptComplete = JS::HeapFunction; -void execute_script(Page& page, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete); -void execute_async_script(Page& page, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete); +void execute_script(HTML::BrowsingContext const&, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete); +void execute_async_script(HTML::BrowsingContext const&, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete); } diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index c28d9261ffe..4b6e5c0692f 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -1836,7 +1836,7 @@ Messages::WebDriverClient::ExecuteScriptResponse WebDriverConnection::execute_sc auto timeout_ms = m_timeouts_configuration.script_timeout; // This handles steps 5 to 9 and produces the appropriate result type for the following steps. - Web::WebDriver::execute_script(current_browsing_context().page(), move(body), move(arguments), timeout_ms, JS::create_heap_function(vm.heap(), [&](Web::WebDriver::ExecuteScriptResultSerialized result) { + Web::WebDriver::execute_script(current_browsing_context(), move(body), move(arguments), timeout_ms, JS::create_heap_function(vm.heap(), [&](Web::WebDriver::ExecuteScriptResultSerialized result) { dbgln_if(WEBDRIVER_DEBUG, "Executing script returned: {}", result.value); Web::WebDriver::Response response; @@ -1884,7 +1884,7 @@ Messages::WebDriverClient::ExecuteAsyncScriptResponse WebDriverConnection::execu auto timeout_ms = m_timeouts_configuration.script_timeout; // This handles steps 5 to 9 and produces the appropriate result type for the following steps. - Web::WebDriver::execute_async_script(current_browsing_context().page(), move(body), move(arguments), timeout_ms, JS::create_heap_function(vm.heap(), [&](Web::WebDriver::ExecuteScriptResultSerialized result) { + Web::WebDriver::execute_async_script(current_browsing_context(), move(body), move(arguments), timeout_ms, JS::create_heap_function(vm.heap(), [&](Web::WebDriver::ExecuteScriptResultSerialized result) { dbgln_if(WEBDRIVER_DEBUG, "Executing async script returned: {}", result.value); Web::WebDriver::Response response;