diff --git a/testing/marionette/assert.js b/testing/marionette/assert.js
index 0cfba6f4cce2..c7e13e2c0c21 100644
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -287,25 +287,6 @@ assert.callable = function(obj, msg = "") {
return assert.that(o => typeof o == "function", msg)(obj);
};
-/**
- * Asserts that obj is an unsigned short number.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {number}
- * obj is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If obj is not an unsigned short.
- */
-assert.unsignedShort = function(obj, msg = "") {
- msg = msg || pprint`Expected ${obj} to be >= 0 and < 65536`;
- return assert.that(n => n >= 0 && n < 65536, msg)(obj);
-};
-
/**
* Asserts that obj is an integer.
*
diff --git a/testing/marionette/browser.js b/testing/marionette/browser.js
index 068bf702049b..8d30646baf7e 100644
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -567,17 +567,17 @@ browser.Context = class {
};
/**
- * The window storage is used to save browsing context ids mapped to weak
+ * The window storage is used to save outer window IDs mapped to weak
* references of Window objects.
*
* Usage:
*
* let wins = new browser.Windows();
- * wins.set(browser.browsingContext.id, window);
+ * wins.set(browser.outerWindowID, window);
*
* ...
*
- * let win = wins.get(browser.browsingContext.id);
+ * let win = wins.get(browser.outerWindowID);
*
*/
browser.Windows = class extends Map {
@@ -585,7 +585,7 @@ browser.Windows = class extends Map {
* Save a weak reference to the Window object.
*
* @param {string} id
- * Browsing context id.
+ * Outer window ID.
* @param {Window} win
* Window object to save.
*
@@ -602,7 +602,7 @@ browser.Windows = class extends Map {
* Get the window object stored by provided |id|.
*
* @param {string} id
- * Browsing context id.
+ * Outer window ID.
*
* @return {Window}
* Saved window object.
diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js
index c3789818aefb..f381bb51b7e0 100644
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -288,7 +288,7 @@ Object.defineProperty(GeckoDriver.prototype, "chromeWindowHandles", {
let hs = [];
for (let win of this.windows) {
- hs.push(getWindowId(win));
+ hs.push(getOuterWindowId(win));
}
return hs;
@@ -474,16 +474,16 @@ GeckoDriver.prototype.addFrameCloseListener = function(action) {
* @return {string}
* Returns the unique server-assigned ID of the window.
*/
-GeckoDriver.prototype.addBrowser = function(win) {
- let context = new browser.Context(win, this);
- let winId = getWindowId(win);
+GeckoDriver.prototype.addBrowser = function(window) {
+ let bc = new browser.Context(window, this);
+ let winId = getOuterWindowId(window);
- this.browsers[winId] = context;
+ this.browsers[winId] = bc;
this.curBrowser = this.browsers[winId];
if (!this.wins.has(winId)) {
// add this to seenItems so we can guarantee
// the user will get winId as this window's id
- this.wins.set(winId, win);
+ this.wins.set(winId, window);
}
};
@@ -579,6 +579,8 @@ GeckoDriver.prototype.getVisibleText = function(el, lines) {
* their type they are either accepted or ignored.
*/
GeckoDriver.prototype.registerBrowser = function(id, be) {
+ let listenerWindow = Services.wm.getOuterWindowWithId(id);
+
// We want to ignore frames that are XUL browsers that aren't in the "main"
// tabbrowser, but accept things on Fennec (which doesn't have a
// xul:tabbrowser), and accept HTML iframes (because tests depend on it),
@@ -594,9 +596,7 @@ GeckoDriver.prototype.registerBrowser = function(id, be) {
this.curBrowser.register(id, be);
}
- const context = BrowsingContext.get(id);
- this.wins.set(id, context.currentWindowGlobal);
-
+ this.wins.set(id, listenerWindow);
return id;
};
@@ -605,8 +605,8 @@ GeckoDriver.prototype.registerPromise = function() {
return new Promise(resolve => {
let cb = ({ json, target }) => {
- let { frameId } = json;
- this.registerBrowser(frameId, target);
+ let { outerWindowID } = json;
+ this.registerBrowser(outerWindowID, target);
if (this.curBrowser.frameRegsPending > 0) {
this.curBrowser.frameRegsPending--;
@@ -617,7 +617,7 @@ GeckoDriver.prototype.registerPromise = function() {
resolve();
}
- return { frameId };
+ return { outerWindowID };
};
this.mm.addMessageListener(li, cb);
});
@@ -628,7 +628,7 @@ GeckoDriver.prototype.listeningPromise = function() {
return new Promise(resolve => {
let cb = msg => {
- if (msg.json.frameId === this.curBrowser.curFrameId) {
+ if (msg.json.outerWindowID === this.curBrowser.curFrameId) {
this.mm.removeMessageListener(li, cb);
resolve();
}
@@ -1390,7 +1390,7 @@ GeckoDriver.prototype.getIdForBrowser = function(browser) {
return this._browserIds.get(permKey);
}
- let winId = browser.browsingContext.id;
+ let winId = browser.outerWindowID;
if (winId) {
this._browserIds.set(permKey, winId);
return winId;
@@ -1618,13 +1618,13 @@ GeckoDriver.prototype.switchToWindow = async function(cmd) {
* associated metadata.
*/
GeckoDriver.prototype.findWindow = function(winIterable, filter) {
- for (const win of winIterable) {
- const bc = win.docShell.browsingContext;
- const tabBrowser = browser.getTabBrowser(win);
+ for (let win of winIterable) {
+ let outerId = getOuterWindowId(win);
+ let tabBrowser = browser.getTabBrowser(win);
// In case the wanted window is a chrome window, we are done.
- if (filter(win, bc.id)) {
- return { win, id: bc.id, hasTabBrowser: !!tabBrowser };
+ if (filter(win, outerId)) {
+ return { win, outerId, hasTabBrowser: !!tabBrowser };
// Otherwise check if the chrome window has a tab browser, and that it
// contains a tab with the wanted window handle.
@@ -1636,7 +1636,7 @@ GeckoDriver.prototype.findWindow = function(winIterable, filter) {
if (filter(win, contentWindowId)) {
return {
win,
- id: bc.id,
+ outerId,
hasTabBrowser: true,
tabIndex: i,
};
@@ -1665,7 +1665,7 @@ GeckoDriver.prototype.setWindowHandle = async function(
winProperties,
focus = true
) {
- if (!(winProperties.id in this.browsers)) {
+ if (!(winProperties.outerId in this.browsers)) {
// Initialise Marionette if the current chrome window has not been seen
// before. Also register the initial tab, if one exists.
let registerBrowsers, browserListening;
@@ -1683,7 +1683,7 @@ GeckoDriver.prototype.setWindowHandle = async function(
}
} else {
// Otherwise switch to the known chrome window
- this.curBrowser = this.browsers[winProperties.id];
+ this.curBrowser = this.browsers[winProperties.outerId];
this.mainFrame = this.curBrowser.window;
this.curFrame = null;
@@ -1758,10 +1758,6 @@ GeckoDriver.prototype.switchToFrame = async function(cmd) {
let { id, focus } = cmd.parameters;
- if (typeof id == "number") {
- assert.unsignedShort(id, `Expected id to be unsigned short, got ${id}`);
- }
-
// TODO(ato): element can be either string (deprecated) or a web
// element JSON Object. Can be removed with Firefox 60.
let byFrame;
@@ -3572,12 +3568,12 @@ GeckoDriver.prototype.receiveMessage = function(message) {
break;
case "Marionette:Register":
- let { frameId } = message.json;
- this.registerBrowser(frameId, message.target);
- return { frameId };
+ let { outerWindowID } = message.json;
+ this.registerBrowser(outerWindowID, message.target);
+ return { outerWindowID };
case "Marionette:ListenersAttached":
- if (message.json.frameId === this.curBrowser.curFrameId) {
+ if (message.json.outerWindowID === this.curBrowser.curFrameId) {
this.curBrowser.flushPendingCommands();
}
break;
@@ -3899,8 +3895,8 @@ GeckoDriver.prototype.commands = {
"WebDriver:TakeScreenshot": GeckoDriver.prototype.takeScreenshot,
};
-function getWindowId(win) {
- return win.docShell.browsingContext.id;
+function getOuterWindowId(win) {
+ return win.windowUtils.outerWindowID;
}
async function exitFullscreen(win) {
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
index 59f2af38f9e3..243c0a032328 100644
--- a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
+++ b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
@@ -92,7 +92,7 @@ class WindowManagerMixin(object):
return self.marionette.execute_script("""
Components.utils.import("resource://gre/modules/Services.jsm");
- const win = BrowsingContext.get(Number(arguments[0])).window;
+ let win = Services.wm.getOuterWindowWithId(Number(arguments[0]));
return win.document.readyState == "complete";
""", script_args=[handle])
@@ -174,7 +174,7 @@ class WindowManagerMixin(object):
await focused;
}
- resolve(win.docShell.browsingContext.id);
+ resolve(win.windowUtils.outerWindowID);
})();
""", script_args=(url, focus))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py
index 923e572bc84e..ec59b70838f0 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py
@@ -6,7 +6,6 @@ from __future__ import absolute_import
from marionette_driver.by import By
from marionette_driver.errors import (
- InvalidArgumentException,
JavascriptException,
NoSuchFrameException,
)
@@ -123,13 +122,11 @@ class TestSwitchFrame(MarionetteTestCase):
def test_switch_to_frame_with_out_of_bounds_index(self):
self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
count = self.marionette.execute_script("return window.frames.length;")
- for index in [count, 65535]:
- self.assertRaises(NoSuchFrameException, self.marionette.switch_to_frame, index)
+ self.assertRaises(NoSuchFrameException, self.marionette.switch_to_frame, count)
- def test_switch_to_frame_with_invalid_index(self):
+ def test_switch_to_frame_with_negative_index(self):
self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
- for index in [-1, 65536]:
- self.assertRaises(InvalidArgumentException, self.marionette.switch_to_frame, index)
+ self.assertRaises(NoSuchFrameException, self.marionette.switch_to_frame, -1)
def test_switch_to_parent_frame(self):
frame_html = self.marionette.absolute_url("frameset.html")
diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js
index 8c04a6ba4365..18ebe963415b 100644
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -58,26 +58,13 @@ const { navigate } = ChromeUtils.import(
);
const { proxy } = ChromeUtils.import("chrome://marionette/content/proxy.js");
-XPCOMUtils.defineLazyGetter(this, "logger", () => Log.getWithPrefix(contentId));
+XPCOMUtils.defineLazyGetter(this, "logger", () =>
+ Log.getWithPrefix(outerWindowID)
+);
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
-const contentId = content.docShell.browsingContext.id;
-
-const curContainer = {
- _frame: null,
- shadowRoot: null,
-
- get frame() {
- return this._frame;
- },
-
- set frame(frame) {
- this._frame = frame;
-
- this.id = this._frame.docShell.browsingContext.id;
- this.shadowRoot = null;
- },
-};
+let { outerWindowID } = winUtil;
+let curContainer = { frame: content, shadowRoot: null };
// Listen for click event to indicate one click has happened, so actions
// code can send dblclick event
@@ -386,16 +373,17 @@ const loadListener = {
},
observe(subject, topic) {
- logger.trace(`Received observer notification ${topic}`);
+ const win = curContainer.frame;
+ const winID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
+ const curWinID = win.windowUtils.outerWindowID;
- const winId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
- const bc = BrowsingContext.get(curContainer.id);
+ logger.trace(`Received observer notification ${topic}`);
switch (topic) {
// In the case when the currently selected frame is closed,
// there will be no further load events. Stop listening immediately.
case "outer-window-destroyed":
- if (bc.window.windowUtils.outerWindowID == winId) {
+ if (curWinID === winID) {
this.stop();
sendOk(this.commandID);
}
@@ -493,27 +481,25 @@ const loadListener = {
function registerSelf() {
logger.trace("Frame script loaded");
- curContainer.frame = content;
-
sandboxes.clear();
+ curContainer = {
+ frame: content,
+ shadowRoot: null,
+ };
legacyactions.mouseEventsOnly = false;
action.inputStateMap = new Map();
action.inputsToCancel = [];
- let reply = sendSyncMessage("Marionette:Register", {
- frameId: contentId,
- });
+ let reply = sendSyncMessage("Marionette:Register", { outerWindowID });
if (reply.length == 0) {
logger.error("No reply from Marionette:Register");
return;
}
- if (reply[0].frameId === contentId) {
+ if (reply[0].outerWindowID === outerWindowID) {
logger.trace("Frame script registered");
startListeners();
- sendAsyncMessage("Marionette:ListenersAttached", {
- frameId: contentId,
- });
+ sendAsyncMessage("Marionette:ListenersAttached", { outerWindowID });
}
}
@@ -680,11 +666,9 @@ function deregister() {
function deleteSession() {
seenEls.clear();
-
// reset container frame to the top-most frame
- curContainer.frame = content;
+ curContainer = { frame: content, shadowRoot: null };
curContainer.frame.focus();
-
legacyactions.touchIds = {};
if (action.inputStateMap !== undefined) {
action.inputStateMap.clear();
@@ -765,7 +749,8 @@ function emitTouchEvent(type, touch) {
);
const win = curContainer.frame;
- if (win.docShell.asyncPanZoomEnabled && legacyactions.scrolling) {
+ let docShell = win.docShell;
+ if (docShell.asyncPanZoomEnabled && legacyactions.scrolling) {
let ev = {
index: 0,
type,
@@ -1530,9 +1515,7 @@ function switchToParentFrame(msg) {
*/
function switchToFrame(msg) {
let commandID = msg.json.commandID;
-
- let foundFrame;
- let frameWebEl;
+ let foundFrame = null;
// check if curContainer.frame reference is dead
let frames = [];
@@ -1552,7 +1535,6 @@ function switchToFrame(msg) {
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
curContainer.frame = content;
-
if (msg.json.focus) {
curContainer.frame.focus();
}
@@ -1588,12 +1570,13 @@ function switchToFrame(msg) {
let wrappedItem = new XPCNativeWrapper(frameEl);
let wrappedWanted = new XPCNativeWrapper(wantedFrame);
if (wrappedItem == wrappedWanted) {
- foundFrame = frameEl;
+ curContainer.frame = frameEl;
+ foundFrame = i;
}
}
}
- if (!foundFrame) {
+ if (foundFrame === null) {
// Either the frame has been removed or we have a OOP frame
// so lets just get all the iframes and do a quick loop before
// throwing in the towel
@@ -1604,47 +1587,48 @@ function switchToFrame(msg) {
let wrappedEl = new XPCNativeWrapper(frameEl);
let wrappedWanted = new XPCNativeWrapper(wantedFrame);
if (wrappedEl == wrappedWanted) {
- foundFrame = iframes[i];
+ curContainer.frame = iframes[i];
+ foundFrame = i;
}
}
}
}
- if (!foundFrame) {
+ if (foundFrame === null) {
if (typeof msg.json.id === "number") {
try {
- if (msg.json.id >= 0 && msg.json.id < frames.length) {
- foundFrame = frames[msg.json.id].frameElement;
- if (foundFrame !== null) {
- frameWebEl = seenEls.add(foundFrame.wrappedJSObject);
- } else {
- // If foundFrame is null at this point then we have the top
- // level browsing context so should treat it accordingly.
- sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
- curContainer.frame = content;
+ foundFrame = frames[msg.json.id].frameElement;
+ if (foundFrame !== null) {
+ curContainer.frame = foundFrame;
+ foundFrame = seenEls.add(curContainer.frame);
+ } else {
+ // If foundFrame is null at this point then we have the top
+ // level browsing context so should treat it accordingly.
+ sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
+ curContainer.frame = content;
- if (msg.json.focus) {
- curContainer.frame.focus();
- }
-
- sendOk(commandID);
- return;
+ if (msg.json.focus) {
+ curContainer.frame.focus();
}
+
+ sendOk(commandID);
+ return;
}
} catch (e) {
// Since window.frames does not return OOP frames it will throw
// and we land up here. Let's not give up and check if there are
// iframes and switch to the indexed frame there
- let doc = foundFrame.document;
+ let doc = curContainer.frame.document;
let iframes = doc.getElementsByTagName("iframe");
if (msg.json.id >= 0 && msg.json.id < iframes.length) {
- foundFrame = iframes[msg.json.id];
+ curContainer.frame = iframes[msg.json.id];
+ foundFrame = msg.json.id;
}
}
}
}
- if (!foundFrame) {
+ if (foundFrame === null) {
let failedFrame = msg.json.id || msg.json.element;
let err = new NoSuchFrameError(`Unable to locate frame: ${failedFrame}`);
sendError(err, commandID);
@@ -1653,14 +1637,12 @@ function switchToFrame(msg) {
// send a synchronous message to let the server update the currently active
// frame element (for getActiveFrame)
- if (!frameWebEl) {
- frameWebEl = seenEls.add(foundFrame.wrappedJSObject);
- }
+ let frameWebEl = seenEls.add(curContainer.frame.wrappedJSObject);
sendSyncMessage("Marionette:switchedToFrame", {
frameValue: frameWebEl.uuid,
});
- curContainer.frame = foundFrame.contentWindow;
+ curContainer.frame = curContainer.frame.contentWindow;
if (msg.json.focus) {
curContainer.frame.focus();
}