mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb+WebContent+WebDriver: Allow specifying multiple prompt handlers
WebDriver script authors may now provide either:
* A user prompt handler configuration to be used for all prompt types.
* A set of per-prompt-type user prompt handlers.
This also paves the way for interaction with the beforeunload prompt,
though we do not yet support that feature in LibWeb.
See: 43903d0
This commit is contained in:
parent
eef9d07088
commit
2583996e18
Notes:
github-actions[bot]
2025-02-06 14:02:21 +00:00
Author: https://github.com/trflynn89
Commit: 2583996e18
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3471
Reviewed-by: https://github.com/AtkinsSJ
10 changed files with 349 additions and 92 deletions
|
@ -828,6 +828,7 @@ set(SOURCES
|
|||
WebDriver/Response.cpp
|
||||
WebDriver/Screenshot.cpp
|
||||
WebDriver/TimeoutsConfiguration.cpp
|
||||
WebDriver/UserPrompt.cpp
|
||||
WebGL/Extensions/ANGLEInstancedArrays.cpp
|
||||
WebGL/Extensions/OESVertexArrayObject.cpp
|
||||
WebGL/Extensions/WebGLDrawBuffers.cpp
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include <LibWeb/Loader/UserAgent.h>
|
||||
#include <LibWeb/WebDriver/Capabilities.h>
|
||||
#include <LibWeb/WebDriver/TimeoutsConfiguration.h>
|
||||
#include <LibWeb/WebDriver/UserPrompt.h>
|
||||
|
||||
namespace Web::WebDriver {
|
||||
|
||||
|
@ -30,21 +31,6 @@ static Response deserialize_as_a_page_load_strategy(JsonValue value)
|
|||
return value;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-deserialize-as-an-unhandled-prompt-behavior
|
||||
static Response deserialize_as_an_unhandled_prompt_behavior(JsonValue value)
|
||||
{
|
||||
// 1. If value is not a string return an error with error code invalid argument.
|
||||
if (!value.is_string())
|
||||
return Error::from_code(ErrorCode::InvalidArgument, "Capability unhandledPromptBehavior must be a string"sv);
|
||||
|
||||
// 2. If value is not present as a keyword in the known prompt handling approaches table return an error with error code invalid argument.
|
||||
if (!value.as_string().is_one_of("dismiss"sv, "accept"sv, "dismiss and notify"sv, "accept and notify"sv, "ignore"sv))
|
||||
return Error::from_code(ErrorCode::InvalidArgument, "Invalid pageLoadStrategy capability"sv);
|
||||
|
||||
// 3. Return success with data value.
|
||||
return value;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-deserialize-as-a-proxy
|
||||
static ErrorOr<JsonObject, Error> deserialize_as_a_proxy(JsonValue parameter)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -30,30 +30,6 @@ constexpr PageLoadStrategy page_load_strategy_from_string(StringView strategy)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-unhandled-prompt-behavior
|
||||
enum class UnhandledPromptBehavior {
|
||||
Dismiss,
|
||||
Accept,
|
||||
DismissAndNotify,
|
||||
AcceptAndNotify,
|
||||
Ignore,
|
||||
};
|
||||
|
||||
constexpr UnhandledPromptBehavior unhandled_prompt_behavior_from_string(StringView behavior)
|
||||
{
|
||||
if (behavior == "dismiss"sv)
|
||||
return UnhandledPromptBehavior::Dismiss;
|
||||
if (behavior == "accept"sv)
|
||||
return UnhandledPromptBehavior::Accept;
|
||||
if (behavior == "dismiss and notify"sv)
|
||||
return UnhandledPromptBehavior::DismissAndNotify;
|
||||
if (behavior == "accept and notify"sv)
|
||||
return UnhandledPromptBehavior::AcceptAndNotify;
|
||||
if (behavior == "ignore"sv)
|
||||
return UnhandledPromptBehavior::Ignore;
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
enum class InterfaceMode {
|
||||
Graphical,
|
||||
Headless,
|
||||
|
|
184
Libraries/LibWeb/WebDriver/UserPrompt.cpp
Normal file
184
Libraries/LibWeb/WebDriver/UserPrompt.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibWeb/WebDriver/Error.h>
|
||||
#include <LibWeb/WebDriver/UserPrompt.h>
|
||||
|
||||
namespace Web::WebDriver {
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-user-prompt-handler
|
||||
static UserPromptHandler s_user_prompt_handler;
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-known-prompt-handlers
|
||||
static constexpr Array known_prompt_handlers { "dismiss"sv, "accept"sv, "dismiss and notify"sv, "accept and notify"sv, "ignore"sv };
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-valid-prompt-types
|
||||
static constexpr Array valid_prompt_types { "alert"sv, "beforeUnload"sv, "confirm"sv, "default"sv, "prompt"sv };
|
||||
|
||||
static constexpr PromptHandler prompt_handler_from_string(StringView prompt_handler)
|
||||
{
|
||||
if (prompt_handler == "dismiss"sv)
|
||||
return PromptHandler::Dismiss;
|
||||
if (prompt_handler == "accept"sv)
|
||||
return PromptHandler::Accept;
|
||||
if (prompt_handler == "ignore"sv)
|
||||
return PromptHandler::Ignore;
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
static constexpr PromptType prompt_type_from_string(StringView prompt_type)
|
||||
{
|
||||
if (prompt_type == "alert"sv)
|
||||
return PromptType::Alert;
|
||||
if (prompt_type == "beforeUnload"sv)
|
||||
return PromptType::BeforeUnload;
|
||||
if (prompt_type == "confirm"sv)
|
||||
return PromptType::Confirm;
|
||||
if (prompt_type == "default"sv)
|
||||
return PromptType::Default;
|
||||
if (prompt_type == "prompt"sv)
|
||||
return PromptType::Prompt;
|
||||
if (prompt_type == "fallbackDefault"sv)
|
||||
return PromptType::FallbackDefault;
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
PromptHandlerConfiguration PromptHandlerConfiguration::deserialize(JsonValue const& configuration)
|
||||
{
|
||||
auto handler = prompt_handler_from_string(*configuration.as_object().get_byte_string("handler"sv));
|
||||
|
||||
auto notify = *configuration.as_object().get_bool("notify"sv)
|
||||
? PromptHandlerConfiguration::Notify::Yes
|
||||
: PromptHandlerConfiguration::Notify::No;
|
||||
|
||||
return { .handler = handler, .notify = notify };
|
||||
}
|
||||
|
||||
UserPromptHandler const& user_prompt_handler()
|
||||
{
|
||||
return s_user_prompt_handler;
|
||||
}
|
||||
|
||||
void set_user_prompt_handler(UserPromptHandler user_prompt_handler)
|
||||
{
|
||||
s_user_prompt_handler = move(user_prompt_handler);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-deserialize-as-an-unhandled-prompt-behavior
|
||||
Response deserialize_as_an_unhandled_prompt_behavior(JsonValue value)
|
||||
{
|
||||
// 1. Set value to the result of converting a JSON-derived JavaScript value to an Infra value with value.
|
||||
// 2. If value is not a string, an implementation that does not also support [WebDriver-BiDi] may return error with
|
||||
// error code invalid argument.
|
||||
|
||||
// 3. Let is string value be false.
|
||||
bool is_string_value = false;
|
||||
|
||||
// 3. If value is a string set value to the map «["fallbackDefault" → value]» and set is string value to true.
|
||||
if (value.is_string()) {
|
||||
JsonObject map;
|
||||
map.set("fallbackDefault"sv, move(value));
|
||||
|
||||
value = move(map);
|
||||
is_string_value = true;
|
||||
}
|
||||
|
||||
// 4. If value is not a map return error with error code invalid argument.
|
||||
if (!value.is_object())
|
||||
return WebDriver::Error::from_code(ErrorCode::InvalidArgument, "Capability unhandledPromptBehavior must be a string or object"sv);
|
||||
|
||||
// 5. Let user prompt handler be an empty map.
|
||||
JsonObject user_prompt_handler;
|
||||
|
||||
// 6. For each prompt type → handler in value:
|
||||
TRY(value.as_object().try_for_each_member([&](ByteString const& prompt_type, JsonValue const& handler_value) -> ErrorOr<void, WebDriver::Error> {
|
||||
// 1. If is string value is false and valid prompt types does not contain prompt type return error with error code invalid argument.
|
||||
if (!is_string_value && !valid_prompt_types.contains_slow(prompt_type))
|
||||
return WebDriver::Error::from_code(ErrorCode::InvalidArgument, ByteString::formatted("'{}' is not a valid prompt type", prompt_type));
|
||||
|
||||
// 2. If known prompt handlers does not contain an entry with handler key handler return error with error code invalid argument.
|
||||
if (!handler_value.is_string())
|
||||
return WebDriver::Error::from_code(ErrorCode::InvalidArgument, "Prompt handler must be a string"sv);
|
||||
|
||||
StringView handler = handler_value.as_string();
|
||||
|
||||
if (!known_prompt_handlers.contains_slow(handler))
|
||||
return WebDriver::Error::from_code(ErrorCode::InvalidArgument, ByteString::formatted("'{}' is not a known prompt handler", handler));
|
||||
|
||||
// 3. Let notify be false.
|
||||
bool notify = false;
|
||||
|
||||
// 4. If handler is "accept and notify", set handler to "accept" and notify to true.
|
||||
if (handler == "accept and notify"sv) {
|
||||
handler = "accept"sv;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
// 5. If handler is "dismiss and notify", set handler to "dismiss" and notify to true.
|
||||
else if (handler == "dismiss and notify"sv) {
|
||||
handler = "dismiss"sv;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
// 6. If handler is "ignore", set notify to true.
|
||||
else if (handler == "ignore"sv) {
|
||||
notify = true;
|
||||
}
|
||||
|
||||
// 7. Let configuration be a prompt handler configuration with handler handler and notify notify.
|
||||
JsonObject configuration;
|
||||
configuration.set("handler"sv, handler);
|
||||
configuration.set("notify"sv, notify);
|
||||
|
||||
// 8. Set user prompt handler[prompt type] to configuration.
|
||||
user_prompt_handler.set(prompt_type, move(configuration));
|
||||
|
||||
return {};
|
||||
}));
|
||||
|
||||
// Return success with data user prompt handler.
|
||||
return JsonValue { move(user_prompt_handler) };
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-update-the-user-prompt-handler
|
||||
void update_the_user_prompt_handler(JsonObject const& requested_prompt_handler)
|
||||
{
|
||||
// 1. If the user prompt handler is null, set the user prompt handler to an empty map.
|
||||
if (!s_user_prompt_handler.has_value())
|
||||
s_user_prompt_handler = UserPromptHandler::ValueType {};
|
||||
|
||||
// 2. For each request prompt type → request handler in requested prompt handler:
|
||||
requested_prompt_handler.for_each_member([&](ByteString const& request_prompt_type, JsonValue const& request_handler) {
|
||||
// 1. Set user prompt handler[request prompt type] to request handler.
|
||||
s_user_prompt_handler->set(
|
||||
prompt_type_from_string(request_prompt_type),
|
||||
PromptHandlerConfiguration::deserialize(request_handler));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<void> IPC::encode(Encoder& encoder, Web::WebDriver::PromptHandlerConfiguration const& configuration)
|
||||
{
|
||||
TRY(encoder.encode(configuration.handler));
|
||||
TRY(encoder.encode(configuration.notify));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::WebDriver::PromptHandlerConfiguration> IPC::decode(Decoder& decoder)
|
||||
{
|
||||
auto handler = TRY(decoder.decode<Web::WebDriver::PromptHandler>());
|
||||
auto notify = TRY(decoder.decode<Web::WebDriver::PromptHandlerConfiguration::Notify>());
|
||||
|
||||
return Web::WebDriver::PromptHandlerConfiguration { .handler = handler, .notify = notify };
|
||||
}
|
67
Libraries/LibWeb/WebDriver/UserPrompt.h
Normal file
67
Libraries/LibWeb/WebDriver/UserPrompt.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
#include <LibWeb/WebDriver/Response.h>
|
||||
|
||||
namespace Web::WebDriver {
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-known-prompt-handlers
|
||||
enum class PromptHandler {
|
||||
Accept,
|
||||
Dismiss,
|
||||
Ignore,
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-valid-prompt-types
|
||||
enum class PromptType {
|
||||
Alert,
|
||||
BeforeUnload,
|
||||
Confirm,
|
||||
Default,
|
||||
Prompt,
|
||||
FallbackDefault,
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-prompt-handler-configuration
|
||||
struct PromptHandlerConfiguration {
|
||||
enum class Notify {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
static PromptHandlerConfiguration deserialize(JsonValue const&);
|
||||
|
||||
PromptHandler handler { PromptHandler::Dismiss };
|
||||
Notify notify { Notify::Yes };
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-user-prompt-handler
|
||||
using UserPromptHandler = Optional<HashMap<PromptType, PromptHandlerConfiguration>>;
|
||||
|
||||
UserPromptHandler const& user_prompt_handler();
|
||||
void set_user_prompt_handler(UserPromptHandler);
|
||||
|
||||
Response deserialize_as_an_unhandled_prompt_behavior(JsonValue);
|
||||
void update_the_user_prompt_handler(JsonObject const&);
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Web::WebDriver::PromptHandlerConfiguration const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::WebDriver::PromptHandlerConfiguration> decode(Decoder&);
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
#include <LibWeb/WebDriver/Capabilities.h>
|
||||
#include <LibWeb/WebDriver/Response.h>
|
||||
#include <LibWeb/WebDriver/UserPrompt.h>
|
||||
|
||||
endpoint WebDriverClient {
|
||||
close_session() => ()
|
||||
set_page_load_strategy(Web::WebDriver::PageLoadStrategy page_load_strategy) =|
|
||||
set_unhandled_prompt_behavior(Web::WebDriver::UnhandledPromptBehavior unhandled_prompt_behavior) =|
|
||||
set_user_prompt_handler(Web::WebDriver::UserPromptHandler user_prompt_handler) =|
|
||||
set_strict_file_interactability(bool strict_file_interactability) =|
|
||||
set_is_webdriver_active(bool active) =|
|
||||
get_timeouts() => (Web::WebDriver::Response response)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
|
||||
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -59,6 +59,7 @@
|
|||
#include <LibWeb/WebDriver/JSON.h>
|
||||
#include <LibWeb/WebDriver/Properties.h>
|
||||
#include <LibWeb/WebDriver/Screenshot.h>
|
||||
#include <LibWeb/WebDriver/UserPrompt.h>
|
||||
#include <WebContent/WebDriverConnection.h>
|
||||
|
||||
namespace WebContent {
|
||||
|
@ -232,9 +233,9 @@ void WebDriverConnection::set_page_load_strategy(Web::WebDriver::PageLoadStrateg
|
|||
m_page_load_strategy = page_load_strategy;
|
||||
}
|
||||
|
||||
void WebDriverConnection::set_unhandled_prompt_behavior(Web::WebDriver::UnhandledPromptBehavior const& unhandled_prompt_behavior)
|
||||
void WebDriverConnection::set_user_prompt_handler(Web::WebDriver::UserPromptHandler const& user_prompt_handler)
|
||||
{
|
||||
m_unhandled_prompt_behavior = unhandled_prompt_behavior;
|
||||
Web::WebDriver::set_user_prompt_handler(move(const_cast<Web::WebDriver::UserPromptHandler&>(user_prompt_handler)));
|
||||
}
|
||||
|
||||
void WebDriverConnection::set_strict_file_interactability(bool strict_file_interactability)
|
||||
|
@ -2636,58 +2637,100 @@ ErrorOr<void, Web::WebDriver::Error> WebDriverConnection::ensure_current_top_lev
|
|||
return Web::WebDriver::ensure_browsing_context_is_open(current_top_level_browsing_context());
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-get-the-prompt-handler
|
||||
Web::WebDriver::PromptHandlerConfiguration WebDriverConnection::get_the_prompt_handler(Web::WebDriver::PromptType type) const
|
||||
{
|
||||
static Web::WebDriver::UserPromptHandler::ValueType empty_user_prompt_handler;
|
||||
auto const& user_prompt_handler = Web::WebDriver::user_prompt_handler();
|
||||
|
||||
// 1. If the user prompt handler is null, let handlers be an empty map. Otherwise let handlers be user prompt handler.
|
||||
auto const& handlers = user_prompt_handler.has_value() ? *user_prompt_handler : empty_user_prompt_handler;
|
||||
|
||||
// 2. If handlers contains type return handlers[type].
|
||||
if (auto handler = handlers.get(type); handler.has_value())
|
||||
return *handler;
|
||||
|
||||
// 3. If handlers contains "default" return handlers["default"].
|
||||
if (auto handler = handlers.get(Web::WebDriver::PromptType::Default); handler.has_value())
|
||||
return *handler;
|
||||
|
||||
// 4. If type is "beforeUnload", return a prompt handler configuration with handler "accept" and notify false.
|
||||
if (type == Web::WebDriver::PromptType::BeforeUnload)
|
||||
return { .handler = Web::WebDriver::PromptHandler::Accept, .notify = Web::WebDriver::PromptHandlerConfiguration::Notify::No };
|
||||
|
||||
// 5. If handlers contains "fallbackDefault" return handlers["fallbackDefault"].
|
||||
if (auto handler = handlers.get(Web::WebDriver::PromptType::FallbackDefault); handler.has_value())
|
||||
return *handler;
|
||||
|
||||
// 6. Return a prompt handler configuration with handler "dismiss" and notify true.
|
||||
return { .handler = Web::WebDriver::PromptHandler::Dismiss, .notify = Web::WebDriver::PromptHandlerConfiguration::Notify::Yes };
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-handle-any-user-prompts
|
||||
void WebDriverConnection::handle_any_user_prompts(Function<void()> on_dialog_closed)
|
||||
{
|
||||
auto& page = current_browsing_context().page();
|
||||
auto& heap = current_browsing_context().heap();
|
||||
|
||||
// 1. If there is no current user prompt, abort these steps and return success.
|
||||
// 1. If the current browsing context is not blocked by a dialog return success.
|
||||
if (!page.has_pending_dialog()) {
|
||||
on_dialog_closed();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Perform the following substeps based on the current session’s user prompt handler:
|
||||
switch (m_unhandled_prompt_behavior) {
|
||||
// -> dismiss state
|
||||
case Web::WebDriver::UnhandledPromptBehavior::Dismiss:
|
||||
// Dismiss the current user prompt.
|
||||
page.dismiss_dialog(GC::create_function(heap, move(on_dialog_closed)));
|
||||
break;
|
||||
// 2. Let type be "default".
|
||||
auto type = Web::WebDriver::PromptType::Default;
|
||||
|
||||
// -> accept state
|
||||
case Web::WebDriver::UnhandledPromptBehavior::Accept:
|
||||
// Accept the current user prompt.
|
||||
page.accept_dialog(GC::create_function(heap, move(on_dialog_closed)));
|
||||
// 3. If the current user prompt is an alert dialog, set type to "alert". Otherwise, if the current user prompt is a
|
||||
// beforeunload dialog, set type to "beforeUnload". Otherwise, if the current user prompt is a confirm dialog,
|
||||
// set type to "confirm". Otherwise, if the current user prompt is a prompt dialog, set type to "prompt".
|
||||
// FIXME: Handle beforeunload dialogs when they are implemented.
|
||||
switch (page.pending_dialog()) {
|
||||
case Web::Page::PendingDialog::Alert:
|
||||
type = Web::WebDriver::PromptType::Alert;
|
||||
break;
|
||||
|
||||
// -> dismiss and notify state
|
||||
case Web::WebDriver::UnhandledPromptBehavior::DismissAndNotify:
|
||||
// Dismiss the current user prompt.
|
||||
page.dismiss_dialog(GC::create_function(heap, [this]() {
|
||||
// Return an annotated unexpected alert open error.
|
||||
async_driver_execution_complete(Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv));
|
||||
}));
|
||||
case Web::Page::PendingDialog::Confirm:
|
||||
type = Web::WebDriver::PromptType::Confirm;
|
||||
break;
|
||||
|
||||
// -> accept and notify state
|
||||
case Web::WebDriver::UnhandledPromptBehavior::AcceptAndNotify:
|
||||
// Accept the current user prompt.
|
||||
page.accept_dialog(GC::create_function(heap, [this]() {
|
||||
// Return an annotated unexpected alert open error.
|
||||
async_driver_execution_complete(Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv));
|
||||
}));
|
||||
break;
|
||||
|
||||
// -> ignore state
|
||||
case Web::WebDriver::UnhandledPromptBehavior::Ignore:
|
||||
// Return an annotated unexpected alert open error.
|
||||
async_driver_execution_complete(Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user dialog is open"sv));
|
||||
case Web::Page::PendingDialog::Prompt:
|
||||
type = Web::WebDriver::PromptType::Prompt;
|
||||
break;
|
||||
case Web::Page::PendingDialog::None:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// 3. Return success.
|
||||
// 3. Let handler be get the prompt handler with type.
|
||||
auto handler = get_the_prompt_handler(type);
|
||||
|
||||
auto on_complete = GC::create_function(heap, [this, notify = handler.notify, on_dialog_closed = GC::create_function(heap, move(on_dialog_closed))]() {
|
||||
// 5. If handler's notify is true, return annotated unexpected alert open error.
|
||||
if (notify == Web::WebDriver::PromptHandlerConfiguration::Notify::Yes) {
|
||||
async_driver_execution_complete(Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::UnexpectedAlertOpen, "A user prompt is open"sv));
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. Return success.
|
||||
on_dialog_closed->function()();
|
||||
});
|
||||
|
||||
// 4. Perform the following substeps based on handler's handler:
|
||||
switch (handler.handler) {
|
||||
// -> "accept"
|
||||
case Web::WebDriver::PromptHandler::Accept:
|
||||
// Accept the current user prompt.
|
||||
page.accept_dialog(on_complete);
|
||||
break;
|
||||
// -> "dismiss"
|
||||
case Web::WebDriver::PromptHandler::Dismiss:
|
||||
// Dismiss the current user prompt.
|
||||
page.dismiss_dialog(on_complete);
|
||||
break;
|
||||
// -> "ignore"
|
||||
case Web::WebDriver::PromptHandler::Ignore:
|
||||
// Do nothing.
|
||||
on_complete->function()();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-wait-for-navigation-to-complete
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Florent Castelli <florent.castelli@gmail.com>
|
||||
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -48,7 +48,7 @@ private:
|
|||
|
||||
virtual void close_session() override;
|
||||
virtual void set_page_load_strategy(Web::WebDriver::PageLoadStrategy const& page_load_strategy) override;
|
||||
virtual void set_unhandled_prompt_behavior(Web::WebDriver::UnhandledPromptBehavior const& unhandled_prompt_behavior) override;
|
||||
virtual void set_user_prompt_handler(Web::WebDriver::UserPromptHandler const& user_prompt_handler) override;
|
||||
virtual void set_strict_file_interactability(bool strict_file_interactability) override;
|
||||
virtual void set_is_webdriver_active(bool) override;
|
||||
virtual Messages::WebDriverClient::GetTimeoutsResponse get_timeouts() override;
|
||||
|
@ -126,6 +126,7 @@ private:
|
|||
Web::WebDriver::Response element_send_keys_impl(String const& element_id, ByteString const& text);
|
||||
Web::WebDriver::Response add_cookie_impl(JsonObject const&);
|
||||
|
||||
Web::WebDriver::PromptHandlerConfiguration get_the_prompt_handler(Web::WebDriver::PromptType type) const;
|
||||
void handle_any_user_prompts(Function<void()> on_dialog_closed);
|
||||
|
||||
void maximize_the_window();
|
||||
|
@ -155,9 +156,6 @@ private:
|
|||
// https://w3c.github.io/webdriver/#dfn-page-load-strategy
|
||||
Web::WebDriver::PageLoadStrategy m_page_load_strategy { Web::WebDriver::PageLoadStrategy::Normal };
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-unhandled-prompt-behavior
|
||||
Web::WebDriver::UnhandledPromptBehavior m_unhandled_prompt_behavior { Web::WebDriver::UnhandledPromptBehavior::DismissAndNotify };
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-strict-file-interactability
|
||||
bool m_strict_file_interactability { false };
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
|
||||
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include <LibCore/StandardPaths.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibWeb/WebDriver/TimeoutsConfiguration.h>
|
||||
#include <LibWeb/WebDriver/UserPrompt.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace WebDriver {
|
||||
|
@ -98,12 +99,13 @@ void Session::initialize_from_capabilities(JsonObject& capabilities)
|
|||
}
|
||||
|
||||
// 8. Apply changes to the user agent for any implementation-defined capabilities selected during the capabilities processing step.
|
||||
if (auto behavior = capabilities.get_byte_string("unhandledPromptBehavior"sv); behavior.has_value()) {
|
||||
m_unhandled_prompt_behavior = Web::WebDriver::unhandled_prompt_behavior_from_string(*behavior);
|
||||
connection.async_set_unhandled_prompt_behavior(m_unhandled_prompt_behavior);
|
||||
if (auto behavior = capabilities.get_object("unhandledPromptBehavior"sv); behavior.has_value()) {
|
||||
Web::WebDriver::update_the_user_prompt_handler(*behavior);
|
||||
} else {
|
||||
capabilities.set("unhandledPromptBehavior"sv, "dismiss and notify"sv);
|
||||
}
|
||||
|
||||
connection.async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<ServerPromise> promise)
|
||||
|
@ -144,7 +146,7 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(NonnullRefPtr<S
|
|||
|
||||
web_content_connection->async_set_page_load_strategy(m_page_load_strategy);
|
||||
web_content_connection->async_set_strict_file_interactability(m_strict_file_interactiblity);
|
||||
web_content_connection->async_set_unhandled_prompt_behavior(m_unhandled_prompt_behavior);
|
||||
web_content_connection->async_set_user_prompt_handler(Web::WebDriver::user_prompt_handler());
|
||||
if (m_timeouts_configuration.has_value())
|
||||
web_content_connection->async_set_timeouts(*m_timeouts_configuration);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Florent Castelli <florent.castelli@gmail.com>
|
||||
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -101,7 +101,6 @@ private:
|
|||
RefPtr<Core::LocalServer> m_web_content_server;
|
||||
|
||||
Web::WebDriver::PageLoadStrategy m_page_load_strategy { Web::WebDriver::PageLoadStrategy::Normal };
|
||||
Web::WebDriver::UnhandledPromptBehavior m_unhandled_prompt_behavior { Web::WebDriver::UnhandledPromptBehavior::DismissAndNotify };
|
||||
Optional<JsonValue> m_timeouts_configuration;
|
||||
bool m_strict_file_interactiblity { false };
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue