--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -966,20 +966,28 @@ GeckoDriver.prototype.executeJSScript =
* current window triggers and document.readyState is "complete".
*
* In chrome context it will change the current window's location to
* the supplied URL and wait until document.readyState equals "complete"
* or the page timeout duration has elapsed.
*
* @param {string} url
* URL to navigate to.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.get = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let url = cmd.parameters.url;
let get = this.listener.get({url: url, pageTimeout: this.timeouts.pageLoad});
// If a remoteness update interrupts our page load, this will never return
// We need to re-issue this request to correctly poll for readyState and
// send errors.
@@ -1004,32 +1012,49 @@ GeckoDriver.prototype.get = function* (c
* Get a string representing the current URL.
*
* On Desktop this returns a string representation of the URL of the
* current top level browsing context. This is equivalent to
* document.location.href.
*
* When in the context of the chrome, this returns the canonical URL
* of the current resource.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.getCurrentUrl = function (cmd) {
- let win = assert.window(this.getCurrentWindow());
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
switch (this.context) {
case Context.CHROME:
return win.location.href;
case Context.CONTENT:
return this.listener.getCurrentUrl();
}
};
-/** Gets the current title of the window. */
+/**
+ * Gets the current title of the window.
+ *
+ * @return {string}
+ * Document title of the top-level browsing context.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
GeckoDriver.prototype.getTitle = function* (cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
switch (this.context) {
case Context.CHROME:
resp.body.value = win.document.documentElement.getAttribute("title");
break;
case Context.CONTENT:
resp.body.value = yield this.listener.getTitle();
@@ -1039,39 +1064,59 @@ GeckoDriver.prototype.getTitle = functio
/** Gets the current type of the window. */
GeckoDriver.prototype.getWindowType = function (cmd, resp) {
let win = assert.window(this.getCurrentWindow());
resp.body.value = win.document.documentElement.getAttribute("windowtype");
};
-/** Gets the page source of the content document. */
+/**
+ * Gets the page source of the content document.
+ *
+ * @return {string}
+ * String serialisation of the DOM of the current browsing context's
+ * active document.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
switch (this.context) {
case Context.CHROME:
let s = new win.XMLSerializer();
resp.body.value = s.serializeToString(win.document);
break;
case Context.CONTENT:
resp.body.value = yield this.listener.getPageSource();
break;
}
};
/**
* Cause the browser to traverse one step backward in the joint history
* of the current browsing context.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.goBack = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
if (!this.curBrowser.tab) {
// Navigation does not work for non-browser windows
return;
}
if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
return;
@@ -1097,20 +1142,28 @@ GeckoDriver.prototype.goBack = function*
});
yield goBack;
};
/**
* Cause the browser to traverse one step forward in the joint history
* of the current browsing context.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.goForward = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
if (!this.curBrowser.tab) {
// Navigation does not work for non-browser windows
return;
}
if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
return;
@@ -1134,21 +1187,30 @@ GeckoDriver.prototype.goForward = functi
"Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
parameters);
});
yield goForward;
};
/**
- * Causes the browser to reload the page in in current top-level browsing context.
+ * Causes the browser to reload the page in current top-level browsing
+ * context.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.refresh = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
yield this.listener.refresh({pageTimeout: this.timeouts.pageLoad});
};
/**
* Forces an update for the given browser's id.
*/
GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
@@ -1259,49 +1321,68 @@ GeckoDriver.prototype.getChromeWindowHan
*
* Will return the current browser window size in pixels. Refers to
* window outerWidth and outerHeight values, which include scroll bars,
* title bars, etc.
*
* @return {Object.<string, number>}
* Object with |x| and |y| coordinates, and |width| and |height|
* of browser window.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.getWindowRect = function (cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
+
return {
x: win.screenX,
y: win.screenY,
width: win.outerWidth,
height: win.outerHeight,
};
};
/**
- * Set the window position and size of the browser on the OS Window Manager
+ * Set the window position and size of the browser on the operating
+ * system window manager.
*
- * The supplied width and height values refer to the window outerWidth
+ * The supplied |width| and |height| values refer to the window outerWidth
* and outerHeight values, which include browser chrome and OS-level
* window borders.
+ *
* @param {number} x
* X coordinate of the top/left of the window that it will be
* moved to.
* @param {number} y
* Y coordinate of the top/left of the window that it will be
* moved to.
+ * @param {number} width
+ * Width to resize the window to.
+ * @param {number} height
+ * Height to resize the window to.
*
* @return {Object.<string, number>}
- * Object with |x| and |y| coordinates
- * and |width| and |height| dimensions
+ * Object with |x| and |y| coordinates and |width| and |height|
+ * dimensions.
*
+ * @throws {UnsupportedOperationError}
+ * Not applicable to application.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.setWindowRect = function* (cmd, resp) {
- assert.firefox()
-
- let win = assert.window(this.getCurrentWindow());
+ assert.firefox();
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {x, y, height, width} = cmd.parameters;
if (height != null && width != null) {
assert.positiveInteger(height);
assert.positiveInteger(width);
yield new Promise(resolve => {
// When the DOM resize event claims that it fires _after_ the document
@@ -1446,33 +1527,49 @@ GeckoDriver.prototype.getActiveFrame = f
if (this.currentFrameElement !== null) {
let el = element.makeWebElement(this.currentFrameElement);
resp.body.value = el;
}
break;
}
};
-GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
+/**
+ * Set the current browsing context for future commands to the parent
+ * of the current browsing context.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.switchToParentFrame = function* (cmd, resp) {
assert.window(this.getCurrentWindow());
-
- let res = yield this.listener.switchToParentFrame();
+ assert.noUserPrompt(this.dialog);
+
+ yield this.listener.switchToParentFrame();
};
/**
* Switch to a given frame within the current window.
*
* @param {Object} element
* A web element reference to the element to switch to.
* @param {(string|number)} id
* If element is not defined, then this holds either the id, name,
* or index of the frame to switch to.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.switchToFrame = function* (cmd, resp) {
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {id, element, focus} = cmd.parameters;
const otherErrorsExpr = /about:.+(error)|(blocked)\?/;
const checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
let curWindow = this.getCurrentWindow();
@@ -1678,59 +1775,70 @@ GeckoDriver.prototype.singleTap = functi
/**
* Perform a series of grouped actions at the specified points in time.
*
* @param {Array.<?>} actions
* Array of objects that each represent an action sequence.
*
* @throws {UnsupportedOperationError}
- * If the command is made in chrome context.
+ * Not yet available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.performActions = function(cmd, resp) {
+GeckoDriver.prototype.performActions = function (cmd, resp) {
+ assert.content(this.context,
+ "Command 'performActions' is not yet available in chrome context");
assert.window(this.getCurrentWindow());
-
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'performActions' is not yet available in chrome context");
-
- case Context.CONTENT:
- return this.listener.performActions({"actions": cmd.parameters.actions});
- }
+ assert.noUserPrompt(this.dialog);
+
+ let actions = cmd.parameters.actions;
+ yield this.listener.performActions({"actions": actions});
};
/**
* Release all the keys and pointer buttons that are currently depressed.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.releaseActions = function(cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
-
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'releaseActions' is not yet available in chrome context");
-
- case Context.CONTENT:
- return this.listener.releaseActions();
- }
+ assert.noUserPrompt(this.dialog);
+
+ yield this.listener.releaseActions();
};
/**
* An action chain.
*
* @param {Object} value
* A nested array where the inner array represents each event,
* and the outer array represents a collection of events.
*
* @return {number}
* Last touch ID.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not applicable to application.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.actionChain = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {chain, nextId} = cmd.parameters;
switch (this.context) {
case Context.CHROME:
// be conservative until this has a use case and is established
// to work as expected in Fennec
assert.firefox();
@@ -1748,42 +1856,51 @@ GeckoDriver.prototype.actionChain = func
/**
* A multi-action chain.
*
* @param {Object} value
* A nested array where the inner array represents eache vent,
* the middle array represents a collection of events for each
* finger, and the outer array represents all fingers.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.multiAction = function*(cmd, resp) {
+GeckoDriver.prototype.multiAction = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
-
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'multiAction' is not yet available in chrome context");
-
- case Context.CONTENT:
- this.addFrameCloseListener("multi action chain");
- yield this.listener.multiAction(cmd.parameters.value, cmd.parameters.max_length);
- break;
- }
+ assert.noUserPrompt(this.dialog);
+
+ let {value, max_length} = cmd.parameters;
+
+ this.addFrameCloseListener("multi action chain");
+ yield this.listener.multiAction(value, max_length);
};
/**
* Find an element using the indicated search strategy.
*
* @param {string} using
* Indicates which search method to use.
* @param {string} value
* Value the client is looking for.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.findElement = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.findElement = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let strategy = cmd.parameters.using;
let expr = cmd.parameters.value;
let opts = {
startNode: cmd.parameters.element,
timeout: this.timeouts.implicit,
all: false,
};
@@ -1854,39 +1971,51 @@ GeckoDriver.prototype.findElements = fun
resp.body = yield this.listener.findElementsContent(
cmd.parameters.using,
cmd.parameters.value,
opts);
break;
}
};
-/** Return the active element on the page. */
-GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
+/**
+ * Return the active element on the page.
+ *
+ * @return {WebElement}
+ * Active element of the current browsing context's document element.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.getActiveElement = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
-
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'getActiveElement' is not yet available in chrome context");
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getActiveElement();
- break;
- }
+ assert.noUserPrompt(this.dialog);
+
+ resp.body.value = yield this.listener.getActiveElement();
};
/**
* Send click event to element.
*
* @param {string} id
* Reference ID to the element that will be clicked.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.clickElement = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.clickElement = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
yield interaction.clickElement(el, this.a11yChecks);
break;
@@ -1907,26 +2036,31 @@ GeckoDriver.prototype.clickElement = fun
*
* @param {string} id
* Web element reference ID to the element that will be inspected.
* @param {string} name
* Name of the attribute which value to retrieve.
*
* @return {string}
* Value of the attribute.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementAttribute = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {id, name} = cmd.parameters;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
-
resp.body.value = el.getAttribute(name);
break;
case Context.CONTENT:
resp.body.value = yield this.listener.getElementAttribute(id, name);
break;
}
};
@@ -1936,19 +2070,25 @@ GeckoDriver.prototype.getElementAttribut
*
* @param {string} id
* Web element reference ID to the element that will be inspected.
* @param {string} name
* Name of the property which value to retrieve.
*
* @return {string}
* Value of the property.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementProperty = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {id, name} = cmd.parameters;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
resp.body.value = el[name];
break;
@@ -1960,19 +2100,28 @@ GeckoDriver.prototype.getElementProperty
};
/**
* Get the text of an element, if any. Includes the text of all child
* elements.
*
* @param {string} id
* Reference ID to the element that will be inspected.
+ *
+ * @return {string}
+ * Element's text "as rendered".
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getElementText = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementText = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
// for chrome, we look at text nodes, and any node with a "label" field
let el = this.curBrowser.seenEls.get(id, {frame: win});
let lines = [];
@@ -1986,19 +2135,28 @@ GeckoDriver.prototype.getElementText = f
}
};
/**
* Get the tag name of the element.
*
* @param {string} id
* Reference ID to the element that will be inspected.
+ *
+ * @return {string}
+ * Local tag name of element.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementTagName = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
resp.body.value = el.tagName.toLowerCase();
break;
@@ -2009,19 +2167,28 @@ GeckoDriver.prototype.getElementTagName
}
};
/**
* Check if element is displayed.
*
* @param {string} id
* Reference ID to the element that will be inspected.
+ *
+ * @return {boolean}
+ * True if displayed, false otherwise.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementDisplayed = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
resp.body.value = yield interaction.isElementDisplayed(
el, this.a11yChecks);
@@ -2035,19 +2202,28 @@ GeckoDriver.prototype.isElementDisplayed
/**
* Return the property of the computed style of an element.
*
* @param {string} id
* Reference ID to the element that will be checked.
* @param {string} propertyName
* CSS rule that is being requested.
+ *
+ * @return {string}
+ * Value of |propertyName|.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementValueOfCssProperty = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let {id, propertyName: prop} = cmd.parameters;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
let sty = win.document.defaultView.getComputedStyle(el);
resp.body.value = sty.getPropertyValue(prop);
@@ -2059,44 +2235,62 @@ GeckoDriver.prototype.getElementValueOfC
}
};
/**
* Check if element is enabled.
*
* @param {string} id
* Reference ID to the element that will be checked.
+ *
+ * @return {boolean}
+ * True if enabled, false if disabled.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementEnabled = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
// Selenium atom doesn't quite work here
let el = this.curBrowser.seenEls.get(id, {frame: win});
resp.body.value = yield interaction.isElementEnabled(
el, this.a11yChecks);
break;
case Context.CONTENT:
resp.body.value = yield this.listener.isElementEnabled(id);
break;
}
-},
+};
/**
* Check if element is selected.
*
* @param {string} id
* Reference ID to the element that will be checked.
+ *
+ * @return {boolean}
+ * True if selected, false if unselected.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementSelected = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
// Selenium atom doesn't quite work here
let el = this.curBrowser.seenEls.get(id, {frame: win});
resp.body.value = yield interaction.isElementSelected(
@@ -2104,18 +2298,25 @@ GeckoDriver.prototype.isElementSelected
break;
case Context.CONTENT:
resp.body.value = yield this.listener.isElementSelected(id);
break;
}
};
-GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+/**
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.getElementRect = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
let rect = el.getBoundingClientRect();
resp.body = {
@@ -2134,19 +2335,26 @@ GeckoDriver.prototype.getElementRect = f
/**
* Send key presses to element after focusing on it.
*
* @param {string} id
* Reference ID to the element that will be checked.
* @param {string} value
* Value to send to the element.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.sendKeysToElement = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
+
let {id, text} = cmd.parameters;
assert.string(text);
switch (this.context) {
case Context.CHROME:
let el = this.curBrowser.seenEls.get(id, {frame: win});
yield interaction.sendKeysToElement(
el, text, true, this.a11yChecks);
@@ -2167,19 +2375,25 @@ GeckoDriver.prototype.setTestName = func
yield this.listener.setTestName({value: val});
};
/**
* Clear the text of an element.
*
* @param {string} id
* Reference ID to the element that will be cleared.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.clearElement = function*(cmd, resp) {
- let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.clearElement = function* (cmd, resp) {
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let id = cmd.parameters.id;
switch (this.context) {
case Context.CHROME:
// the selenium atom doesn't work here
let el = this.curBrowser.seenEls.get(id, {frame: win});
if (el.nodeName == "textbox") {
@@ -2195,29 +2409,38 @@ GeckoDriver.prototype.clearElement = fun
}
};
/**
* Switch to shadow root of the given host element.
*
* @param {string} id element id.
*/
-GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
- assert.content(this.context)
+GeckoDriver.prototype.switchToShadowRoot = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
- let id;
- if (cmd.parameters) { id = cmd.parameters.id; }
+ let id = cmd.parameters.id;
yield this.listener.switchToShadowRoot(id);
};
-/** Add a cookie to the document. */
-GeckoDriver.prototype.addCookie = function*(cmd, resp) {
- assert.content(this.context)
+/**
+ * Add a cookie to the document.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.addCookie = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let cb = msg => {
this.mm.removeMessageListener("Marionette:addCookie", cb);
let cookie = msg.json;
Services.cookies.add(
cookie.domain,
cookie.path,
cookie.name,
@@ -2234,28 +2457,46 @@ GeckoDriver.prototype.addCookie = functi
yield this.listener.addCookie(cmd.parameters.cookie);
};
/**
* Get all the cookies for the current domain.
*
* This is the equivalent of calling {@code document.cookie} and parsing
* the result.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
-GeckoDriver.prototype.getCookies = function*(cmd, resp) {
- assert.content(this.context)
+GeckoDriver.prototype.getCookies = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
resp.body = yield this.listener.getCookies();
};
-/** Delete all cookies that are visible to a document. */
-GeckoDriver.prototype.deleteAllCookies = function*(cmd, resp) {
- assert.content(this.context)
+/**
+ * Delete all cookies that are visible to a document.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.deleteAllCookies = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let cb = msg => {
let cookie = msg.json;
cookieManager.remove(
cookie.host,
cookie.name,
cookie.path,
false,
@@ -2263,20 +2504,30 @@ GeckoDriver.prototype.deleteAllCookies =
return true;
};
this.mm.addMessageListener("Marionette:deleteCookie", cb);
yield this.listener.deleteAllCookies();
this.mm.removeMessageListener("Marionette:deleteCookie", cb);
};
-/** Delete a cookie by name. */
-GeckoDriver.prototype.deleteCookie = function*(cmd, resp) {
- assert.content(this.context)
+/**
+ * Delete a cookie by name.
+ *
+ * @throws {UnsupportedOperationError}
+ * Not available in current context.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.deleteCookie = function* (cmd, resp) {
+ assert.content(this.context);
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let cb = msg => {
this.mm.removeMessageListener("Marionette:deleteCookie", cb);
let cookie = msg.json;
cookieManager.remove(
cookie.host,
cookie.name,
cookie.path,
@@ -2287,26 +2538,33 @@ GeckoDriver.prototype.deleteCookie = fun
this.mm.addMessageListener("Marionette:deleteCookie", cb);
yield this.listener.deleteCookie(cmd.parameters.name);
};
/**
* Close the currently selected tab/window.
*
- * With multiple open tabs present the currently selected tab will be closed.
- * Otherwise the window itself will be closed. If it is the last window
- * currently open, the window will not be closed to prevent a shutdown of the
- * application. Instead the returned list of window handles is empty.
+ * With multiple open tabs present the currently selected tab will
+ * be closed. Otherwise the window itself will be closed. If it is the
+ * last window currently open, the window will not be closed to prevent
+ * a shutdown of the application. Instead the returned list of window
+ * handles is empty.
*
* @return {Array.<string>}
* Unique window handles of remaining windows.
+ *
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.close = function (cmd, resp) {
assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
let nwins = 0;
let winEn = Services.wm.getEnumerator(null);
while (winEn.hasMoreElements()) {
let win = winEn.getNext();
// For browser windows count the tabs. Otherwise take the window itself.
@@ -2595,21 +2853,27 @@ GeckoDriver.prototype.setScreenOrientati
throw new WebDriverError(`Unable to set screen orientation: ${or}`);
}
};
/**
* Maximizes the user agent window as if the user pressed the maximise
* button.
*
- * Not Supported on B2G or Fennec.
+ * @throws {UnsupportedOperationError}
+ * Not available for current application.
+ * @throws {NoSuchWindowError}
+ * Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ * A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.maximizeWindow = function (cmd, resp) {
- assert.firefox()
- let win = assert.window(this.getCurrentWindow());
+ assert.firefox();
+ const win = assert.window(this.getCurrentWindow());
+ assert.noUserPrompt(this.dialog);
win.maximize()
};
/**
* Dismisses a currently displayed tab modal, or returns no such alert if
* no modal is displayed.
*/
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -21,16 +21,17 @@ const ERRORS = new Set([
"NoSuchElementError",
"NoSuchFrameError",
"NoSuchWindowError",
"ScriptTimeoutError",
"SessionNotCreatedError",
"StaleElementReferenceError",
"TimeoutError",
"UnableToSetCookieError",
+ "UnexpectedAlertOpenError",
"UnknownCommandError",
"UnknownError",
"UnsupportedOperationError",
"WebDriverError",
]);
const BUILTIN_ERRORS = new Set([
"Error",
@@ -445,16 +446,23 @@ class TimeoutError extends WebDriverErro
class UnableToSetCookieError extends WebDriverError {
constructor (message) {
super(message);
this.status = "unable to set cookie";
}
}
+class UnexpectedAlertOpenError extends WebDriverError {
+ constructor (message) {
+ super(message);
+ this.status = "unexpected alert open";
+ }
+}
+
class UnknownCommandError extends WebDriverError {
constructor (message) {
super(message);
this.status = "unknown command";
}
}
class UnknownError extends WebDriverError {
@@ -467,32 +475,33 @@ class UnknownError extends WebDriverErro
class UnsupportedOperationError extends WebDriverError {
constructor (message) {
super(message);
this.status = "unsupported operation";
}
}
const STATUSES = new Map([
+ ["element click intercepted", ElementClickInterceptedError],
["element not accessible", ElementNotAccessibleError],
["element not interactable", ElementNotInteractableError],
- ["element click intercepted", ElementClickInterceptedError],
["insecure certificate", InsecureCertificateError],
["invalid argument", InvalidArgumentError],
["invalid element state", InvalidElementStateError],
["invalid selector", InvalidSelectorError],
["invalid session id", InvalidSessionIDError],
["javascript error", JavaScriptError],
["move target out of bounds", MoveTargetOutOfBoundsError],
["no alert open", NoAlertOpenError],
["no such element", NoSuchElementError],
["no such frame", NoSuchFrameError],
["no such window", NoSuchWindowError],
["script timeout", ScriptTimeoutError],
["session not created", SessionNotCreatedError],
["stale element reference", StaleElementReferenceError],
["timeout", TimeoutError],
["unable to set cookie", UnableToSetCookieError],
+ ["unexpected alert open", UnexpectedAlertOpenError],
["unknown command", UnknownCommandError],
["unknown error", UnknownError],
["unsupported operation", UnsupportedOperationError],
["webdriver error", WebDriverError],
]);
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
@@ -1,28 +1,28 @@
# 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/.
from marionette_driver.by import By
-from marionette_driver.errors import NoAlertPresentException, ElementNotInteractableException
from marionette_driver.expected import element_present
+from marionette_driver import errors
from marionette_driver.marionette import Alert
from marionette_driver.wait import Wait
from marionette_harness import MarionetteTestCase, skip_if_e10s, WindowManagerMixin
class BaseAlertTestCase(WindowManagerMixin, MarionetteTestCase):
def alert_present(self):
try:
Alert(self.marionette).text
return True
- except NoAlertPresentException:
+ except errors.NoAlertPresentException:
return False
def wait_for_alert(self, timeout=None):
Wait(self.marionette, timeout=timeout).until(
lambda _: self.alert_present())
def wait_for_alert_closed(self, timeout=None):
Wait(self.marionette, timeout=timeout).until(
@@ -48,18 +48,20 @@ class TestTabModalAlerts(BaseAlertTestCa
self.wait_for_alert_closed()
except:
pass
super(TestTabModalAlerts, self).tearDown()
def test_no_alert_raises(self):
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).accept)
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).dismiss)
+ with self.assertRaises(errors.NoAlertPresentException):
+ Alert(self.marionette).accept()
+ with self.assertRaises(errors.NoAlertPresentException):
+ Alert(self.marionette).dismiss()
def test_alert_accept(self):
self.marionette.find_element(By.ID, "tab-modal-alert").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
alert.accept()
def test_alert_dismiss(self):
@@ -107,51 +109,53 @@ class TestTabModalAlerts(BaseAlertTestCa
# Restart the session to ensure we still find the formerly left-open dialog.
self.marionette.delete_session()
self.marionette.start_session()
alert = self.marionette.switch_to_alert()
alert.dismiss()
def test_alert_text(self):
- with self.assertRaises(NoAlertPresentException):
+ with self.assertRaises(errors.NoAlertPresentException):
alert = self.marionette.switch_to_alert()
alert.text
self.marionette.find_element(By.ID, "tab-modal-alert").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
self.assertEqual(alert.text, "Marionette alert")
alert.accept()
def test_prompt_text(self):
- with self.assertRaises(NoAlertPresentException):
+ with self.assertRaises(errors.NoAlertPresentException):
alert = self.marionette.switch_to_alert()
alert.text
self.marionette.find_element(By.ID, "tab-modal-prompt").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
self.assertEqual(alert.text, "Marionette prompt")
alert.accept()
def test_confirm_text(self):
- with self.assertRaises(NoAlertPresentException):
+ with self.assertRaises(errors.NoAlertPresentException):
alert = self.marionette.switch_to_alert()
alert.text
self.marionette.find_element(By.ID, "tab-modal-confirm").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
self.assertEqual(alert.text, "Marionette confirm")
alert.accept()
def test_set_text_throws(self):
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).send_keys, "Foo")
+ with self.assertRaises(errors.NoAlertPresentException):
+ Alert(self.marionette).send_keys("Foo")
self.marionette.find_element(By.ID, "tab-modal-alert").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
- self.assertRaises(ElementNotInteractableException, alert.send_keys, "Foo")
+ with self.assertRaises(errors.ElementNotInteractableException):
+ alert.send_keys("Foo")
alert.accept()
def test_set_text_accept(self):
self.marionette.find_element(By.ID, "tab-modal-prompt").click()
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
alert.send_keys("Some text!")
alert.accept()
@@ -189,41 +193,21 @@ class TestTabModalAlerts(BaseAlertTestCa
"""))
self.marionette.navigate("about:blank")
self.wait_for_alert()
alert = self.marionette.switch_to_alert()
self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
alert.accept()
self.wait_for_condition(lambda mn: mn.get_url() == "about:blank")
- @skip_if_e10s("Bug 1325044")
def test_unrelated_command_when_alert_present(self):
- click_handler = self.marionette.find_element(By.ID, "click-handler")
- text = self.marionette.find_element(By.ID, "click-result").text
- self.assertEqual(text, "")
-
self.marionette.find_element(By.ID, "tab-modal-alert").click()
self.wait_for_alert()
-
- # Commands succeed, but because the dialog blocks the event loop,
- # our actions aren't reflected on the page.
- text = self.marionette.find_element(By.ID, "click-result").text
- self.assertEqual(text, "")
- click_handler.click()
- text = self.marionette.find_element(By.ID, "click-result").text
- self.assertEqual(text, "")
-
- alert = self.marionette.switch_to_alert()
- alert.accept()
-
- self.wait_for_alert_closed()
-
- click_handler.click()
- text = self.marionette.find_element(By.ID, "click-result").text
- self.assertEqual(text, "result")
+ with self.assertRaises(errors.UnexpectedAlertOpen):
+ self.marionette.find_element(By.ID, "click-result")
class TestModalAlerts(BaseAlertTestCase):
def setUp(self):
super(TestModalAlerts, self).setUp()
def tearDown(self):