Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
pprint: "chrome://remote/content/shared/Format.sys.mjs",
});
/**
* @typedef {string} PromptHandlers
*/
/**
* Enum of known prompt handlers.
*
* @readonly
* @enum {PromptHandlers}
*
*/
export const PromptHandlers = {
/** All simple dialogs encountered should be accepted. */
Accept: "accept",
/**
* All simple dialogs encountered should be accepted, and an error
* returned that the dialog was handled.
*/
AcceptAndNotify: "accept and notify",
/** All simple dialogs encountered should be dismissed. */
Dismiss: "dismiss",
/**
* All simple dialogs encountered should be dismissed, and an error
* returned that the dialog was handled.
*/
DismissAndNotify: "dismiss and notify",
/** All simple dialogs encountered should be left to the user to handle. */
Ignore: "ignore",
};
/**
* @typedef {string} PromptTypes
*/
/**
* Enum of valid prompt types.
*
* @readonly
* @enum {PromptTypes}
*
*/
export const PromptTypes = {
// A simple alert dialog
Alert: "alert",
// A simple beforeunload dialog. If no handler is set it falls back to the
// `accept` handler to keep backward compatibility with WebDriver classic,
// which doesn't customize this prompt type.
BeforeUnload: "beforeUnload",
// A simple confirm dialog
Confirm: "confirm",
// Default value when no specific handler is configured. Can only be set when
// specifying the unhandlePromptBehavior capability with a map containing a
// "default" entry. See FALLBACK_DEFAULT_PROMPT_TYPE.
Default: "default",
// A simple prompt dialog
Prompt: "prompt",
};
/**
* Internal prompt type used when the unhandledPromptBehavior capability is
* set as a string. The "fallbackDefault" type will apply to "alert", "confirm"
* and "prompt" prompts, but will not apply to "beforeUnload" prompts.
*/
const FALLBACK_DEFAULT_PROMPT_TYPE = "fallbackDefault";
export class PromptHandlerConfiguration {
#handler;
#notify;
/**
* Create an instance of a prompt handler configuration.
*
* @param {string} handler
* Handler to use for the user prompt. One of "accept", "dismiss" or "ignore".
* @param {boolean} notify
* Flag to indicate if the user needs to be notified when the dialog was
* handled.
*
*/
constructor(handler, notify) {
this.#handler = handler;
this.#notify = notify;
}
get handler() {
return this.#handler;
}
get notify() {
return this.#notify;
}
toString() {
return "[object PromptHandlerConfiguration]";
}
/**
* JSON serialization of the prompt handler configuration object.
*
* @returns {Record<string, ?>} json
*
*/
toJSON() {
let serialized = this.#handler;
if (["accept", "dismiss"].includes(serialized) && this.#notify) {
serialized += " and notify";
}
return serialized;
}
}
export class UserPromptHandler {
#promptTypeToHandlerMap;
constructor() {
// Note: this map is null until update-the-user-prompt-handler initializes
// it.
this.#promptTypeToHandlerMap = null;
}
get activePromptHandlers() {
return this.#promptTypeToHandlerMap;
}
get PromptHandlers() {
return PromptHandlers;
}
get PromptTypes() {
return PromptTypes;
}
/**
* Unmarshal a JSON object representation of the unhandledPromptBehavior capability.
*
* @param {Record<string, ?>} json
* JSON Object to unmarshal.
*
* @throws {InvalidArgumentError}
* When the value of the unhandledPromptBehavior capability is invalid.
*
* @returns {UserPromptHandler}
*
*/
static fromJSON(json) {
let isStringValue = false;
let value = json;
if (typeof value === "string") {
// A single specified prompt behavior or for WebDriver classic.
value = { [FALLBACK_DEFAULT_PROMPT_TYPE]: value };
isStringValue = true;
}
lazy.assert.object(
value,
lazy.pprint`Expected "unhandledPromptBehavior" to be an object, got ${value}`
);
const userPromptHandlerCapability = new Map();
for (let [promptType, handler] of Object.entries(value)) {
if (!isStringValue) {
const validPromptTypes = Object.values(PromptTypes);
lazy.assert.in(
promptType,
validPromptTypes,
lazy.pprint`Expected "promptType" to be one of ${validPromptTypes}, got ${promptType}`
);
}
const knownPromptHandlers = Object.values(PromptHandlers);
lazy.assert.in(
handler,
knownPromptHandlers,
lazy.pprint`Expected "handler" to be one of ${knownPromptHandlers}, got ${handler}`
);
let notify = false;
switch (handler) {
case PromptHandlers.AcceptAndNotify:
handler = PromptHandlers.Accept;
notify = true;
break;
case PromptHandlers.DismissAndNotify:
handler = PromptHandlers.Dismiss;
notify = true;
break;
case PromptHandlers.Ignore:
notify = true;
break;
}
const configuration = new PromptHandlerConfiguration(handler, notify);
userPromptHandlerCapability.set(promptType, configuration);
}
const userPromptHandler = new UserPromptHandler();
userPromptHandler.update(userPromptHandlerCapability);
return userPromptHandler;
}
/**
* Get the handler for the given prompt type.
*
* @param {string} promptType
* The prompt type to retrieve the handler for.
*
* @returns {PromptHandlerConfiguration}
*
*/
getPromptHandler(promptType) {
let handlers;
if (this.#promptTypeToHandlerMap === null) {
handlers = new Map();
} else {
handlers = this.#promptTypeToHandlerMap;
}
if (handlers.has(promptType)) {
return handlers.get(promptType);
}
if (handlers.has(PromptTypes.Default)) {
return handlers.get(PromptTypes.Default);
}
if (promptType === PromptTypes.BeforeUnload) {
return new PromptHandlerConfiguration(PromptHandlers.Accept, false);
}
if (handlers.has(FALLBACK_DEFAULT_PROMPT_TYPE)) {
return handlers.get(FALLBACK_DEFAULT_PROMPT_TYPE);
}
return new PromptHandlerConfiguration(PromptHandlers.Dismiss, true);
}
/**
* Updates the prompt handler configuration for a given requested prompt
* handler map.
*
* @param {Map} requestedPromptHandler
* The request prompt handler configuration map.
*
*/
update(requestedPromptHandler) {
if (this.#promptTypeToHandlerMap === null) {
this.#promptTypeToHandlerMap = new Map();
}
for (const [promptType, handler] of requestedPromptHandler) {
this.#promptTypeToHandlerMap.set(promptType, handler);
}
}
/**
* JSON serialization of the user prompt handler object.
*
* @returns {Record<string, ?>} json
*
*/
toJSON() {
if (this.#promptTypeToHandlerMap === null) {
// Fallback to "dismiss and notify" if no handler is set
return PromptHandlers.DismissAndNotify;
}
if (
this.#promptTypeToHandlerMap.size === 1 &&
this.#promptTypeToHandlerMap.has(FALLBACK_DEFAULT_PROMPT_TYPE)
) {
return this.#promptTypeToHandlerMap
.get(FALLBACK_DEFAULT_PROMPT_TYPE)
.toJSON();
}
const serialized = {};
for (const [key, value] of this.#promptTypeToHandlerMap.entries()) {
serialized[key] = value.toJSON();
}
return serialized;
}
toString() {
return "[object UserPromptHandler]";
}
}