Skip to content

Commit

Permalink
Bug 1884650 - [remote] Add support for user prompt handler. r=webdriv…
Browse files Browse the repository at this point in the history
…er-reviewers,jdescottes

Differential Revision: https://phabricator.services.mozilla.com/D210730
  • Loading branch information
whimboo committed May 23, 2024
1 parent 9c3e081 commit b77f31a
Show file tree
Hide file tree
Showing 12 changed files with 623 additions and 256 deletions.
1 change: 1 addition & 0 deletions remote/jar.mn
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ remote.jar:
content/shared/webdriver/NodeCache.sys.mjs (shared/webdriver/NodeCache.sys.mjs)
content/shared/webdriver/Session.sys.mjs (shared/webdriver/Session.sys.mjs)
content/shared/webdriver/URLPattern.sys.mjs (shared/webdriver/URLPattern.sys.mjs)
content/shared/webdriver/UserPromptHandler.sys.mjs (shared/webdriver/UserPromptHandler.sys.mjs)
content/shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs (shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs)
content/shared/webdriver/process-actors/WebDriverProcessDataParent.sys.mjs (shared/webdriver/process-actors/WebDriverProcessDataParent.sys.mjs)

Expand Down
62 changes: 32 additions & 30 deletions remote/marionette/driver.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ ChromeUtils.defineESModuleGetters(lazy, {
permissions: "chrome://remote/content/shared/Permissions.sys.mjs",
pprint: "chrome://remote/content/shared/Format.sys.mjs",
print: "chrome://remote/content/shared/PDF.sys.mjs",
PollPromise: "chrome://remote/content/shared/Sync.sys.mjs",
PromptHandlers:
"chrome://remote/content/shared/webdriver/UserPromptHandler.sys.mjs",
PromptListener:
"chrome://remote/content/shared/listeners/PromptListener.sys.mjs",
quit: "chrome://remote/content/shared/Browser.sys.mjs",
Expand All @@ -43,8 +46,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
TabManager: "chrome://remote/content/shared/TabManager.sys.mjs",
TimedPromise: "chrome://remote/content/marionette/sync.sys.mjs",
Timeouts: "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs",
UnhandledPromptBehavior:
"chrome://remote/content/shared/webdriver/Capabilities.sys.mjs",
unregisterCommandsActor:
"chrome://remote/content/marionette/actors/MarionetteCommandsParent.sys.mjs",
waitForInitialNavigationCompleted:
Expand Down Expand Up @@ -2817,43 +2818,44 @@ GeckoDriver.prototype._handleUserPrompts = async function () {
return;
}

if (this.dialog.promptType == "beforeunload") {
// Wait until the "beforeunload" prompt has been accepted.
await this.promptListener.dialogClosed();
const textContent = await this.dialog.getText();
const promptType = this.dialog.promptType;

if (promptType === "beforeunload") {
// Auto-accepting the prompt happens asynchronously. That means that there
// can still be a situation when its not closed yet (eg. for slow builds).
await lazy.PollPromise((resolve, reject) => {
this.dialog?.isOpen ? reject() : resolve();
});
return;
}

const textContent = await this.dialog.getText();
let type = "default";
if (["alert", "confirm", "prompt"].includes(this.dialog.promptType)) {
type = promptType;
}

const behavior = this.currentSession.unhandledPromptBehavior;
switch (behavior) {
case lazy.UnhandledPromptBehavior.Accept:
await this.acceptDialog();
break;
const userPromptHandler = this.currentSession.userPromptHandler;

case lazy.UnhandledPromptBehavior.AcceptAndNotify:
const handler = userPromptHandler.getPromptHandler(type);
switch (handler.handler) {
case lazy.PromptHandlers.Accept:
await this.acceptDialog();
throw new lazy.error.UnexpectedAlertOpenError(
`Accepted user prompt dialog: ${textContent}`
);

case lazy.UnhandledPromptBehavior.Dismiss:
await this.dismissDialog();
break;

case lazy.UnhandledPromptBehavior.DismissAndNotify:
case lazy.PromptHandlers.Dismiss:
await this.dismissDialog();
throw new lazy.error.UnexpectedAlertOpenError(
`Dismissed user prompt dialog: ${textContent}`
);

case lazy.UnhandledPromptBehavior.Ignore:
throw new lazy.error.UnexpectedAlertOpenError(
"Encountered unhandled user prompt dialog"
);
break;
case lazy.PromptHandlers.Ignore:
break;
}

default:
throw new TypeError(`Unknown unhandledPromptBehavior "${behavior}"`);
if (handler.notify) {
throw new lazy.error.UnexpectedAlertOpenError(
`Unexpected ${promptType} dialog detected. Performed handler "${handler.handler}"`,
{
text: textContent,
}
);
}
};

Expand Down
58 changes: 10 additions & 48 deletions remote/shared/webdriver/Capabilities.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
pprint: "chrome://remote/content/shared/Format.sys.mjs",
RemoteAgent: "chrome://remote/content/components/RemoteAgent.sys.mjs",
UserPromptHandler:
"chrome://remote/content/shared/webdriver/UserPromptHandler.sys.mjs",
});

ChromeUtils.defineLazyGetter(lazy, "remoteAgent", () => {
Expand Down Expand Up @@ -405,30 +407,6 @@ export class Proxy {
}
}

/**
* Enum of unhandled prompt behavior.
*
* @enum
*/
export const UnhandledPromptBehavior = {
/** 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",
};

/** WebDriver session capabilities representation. */
export class Capabilities extends Map {
/** @class */
Expand All @@ -444,7 +422,7 @@ export class Capabilities extends Map {
["setWindowRect", !lazy.AppInfo.isAndroid],
["timeouts", new Timeouts()],
["strictFileInteractability", false],
["unhandledPromptBehavior", UnhandledPromptBehavior.DismissAndNotify],
["unhandledPromptBehavior", new lazy.UserPromptHandler()],
[
"userAgent",
Cc["@mozilla.org/network/protocol;1?name=http"].getService(
Expand Down Expand Up @@ -513,6 +491,7 @@ export class Capabilities extends Map {
}

marshalled.timeouts = super.get("timeouts");
marshalled.unhandledPromptBehavior = super.get("unhandledPromptBehavior");

return marshalled;
}
Expand Down Expand Up @@ -588,15 +567,7 @@ export class Capabilities extends Map {
break;

case "unhandledPromptBehavior":
lazy.assert.string(
v,
lazy.pprint`Expected ${k} to be a string, got ${v}`
);
if (!Object.values(UnhandledPromptBehavior).includes(v)) {
throw new lazy.error.InvalidArgumentError(
`Unknown unhandled prompt behavior: ${v}`
);
}
v = lazy.UserPromptHandler.fromJSON(v);
break;

case "webSocketUrl":
Expand Down Expand Up @@ -751,16 +722,7 @@ export class Capabilities extends Map {
return Timeouts.fromJSON(value);

case "unhandledPromptBehavior":
lazy.assert.string(
value,
lazy.pprint`Expected ${name} to be a string, got ${value}`
);
if (!Object.values(UnhandledPromptBehavior).includes(value)) {
throw new lazy.error.InvalidArgumentError(
`Unknown unhandled prompt behavior: ${value}`
);
}
return value;
return lazy.UserPromptHandler.fromJSON(value);

case "webSocketUrl":
lazy.assert.boolean(
Expand Down Expand Up @@ -1002,9 +964,8 @@ export function validateCapabilities(capabilities) {
Object.entries(capabilities).forEach(([name, value]) => {
const deserialized = Capabilities.validate(name, value);
if (deserialized !== null) {
if (name === "proxy" || name === "timeouts") {
// Return pure value, the Proxy and Timeouts objects will be setup
// during session creation.
if (["proxy", "timeouts", "unhandledPromptBehavior"].includes(name)) {
// Return pure values for objects that will be setup during session creation.
result[name] = value;
} else {
result[name] = deserialized;
Expand Down Expand Up @@ -1062,7 +1023,8 @@ export function processCapabilities(params) {
});

// TODO: Bug 1836288. Implement the capability matching logic
// for "browserName", "browserVersion" and "platformName" features,
// for "browserName", "browserVersion", "platformName", and
// "unhandledPromptBehavior" features,
// for now we can just pick the first merged capability.
const matchedCapabilities = mergedCapabilities[0];

Expand Down
21 changes: 11 additions & 10 deletions remote/shared/webdriver/Session.sys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ export class WebDriverSession {
* <dd>Indicates whether the remote end supports all of the resizing
* and repositioning commands.
*
* <dt><code>timeouts</code> (Timeouts object)
* <dd>Describes the timeouts imposed on certian session operations.
*
* <dt><code>strictFileInteractability</code> (boolean)
* <dd>Defines the current session’s strict file interactability.
*
* <dt><code>timeouts</code> (Timeouts object)
* <dd>Describes the timeouts imposed on certian session operations.
*
* TODO: update for WebDriver BiDi type
* <dt><code>unhandledPromptBehavior</code> (string)
* <dd>Describes the current session’s user prompt handler. Must be one of
* "<tt>accept</tt>", "<tt>accept and notify</tt>", "<tt>dismiss</tt>",
Expand Down Expand Up @@ -194,19 +195,19 @@ export class WebDriverSession {
throw new lazy.error.SessionNotCreatedError(e);
}

if (this.proxy.init()) {
lazy.logger.info(
`Proxy settings initialized: ${JSON.stringify(this.proxy)}`
);
}

if (this.capabilities.get("acceptInsecureCerts")) {
lazy.logger.warn(
"TLS certificate errors will be ignored for this session"
);
lazy.allowAllCerts.enable();
}

if (this.proxy.init()) {
lazy.logger.info(
`Proxy settings initialised: ${JSON.stringify(this.proxy)}`
);
}

// If we are testing accessibility with marionette, start a11y service in
// chrome first. This will ensure that we do not have any content-only
// services hanging around.
Expand Down Expand Up @@ -319,7 +320,7 @@ export class WebDriverSession {
this.capabilities.set("timeouts", timeouts);
}

get unhandledPromptBehavior() {
get userPromptHandler() {
return this.capabilities.get("unhandledPromptBehavior");
}

Expand Down
Loading

0 comments on commit b77f31a

Please sign in to comment.