Bug 1363428 - Refactor Marionette switchToWindow implementation, r=ato draft
authorJames Graham <james@hoppipolla.co.uk>
Tue, 09 May 2017 18:59:09 +0100
changeset 600209 a12822b629b373cb3e4f505f697beaed31f08254
parent 600208 5d4eb99c56ec840b17ddde6fcd95c2daaddd927a
child 600210 875d7c1bc9eef5b6454794ba7a2ce2018a559554
push id65688
push userbmo:james@hoppipolla.co.uk
push dateSat, 24 Jun 2017 11:04:46 +0000
reviewersato
bugs1363428
milestone56.0a1
Bug 1363428 - Refactor Marionette switchToWindow implementation, r=ato This allows other commands to implicitly change the window handle, by calling findWindow with appropriate arguments to get a window properties object and then passing that to setWindowHandle. MozReview-Commit-ID: 4NpYxjsMM4T
testing/marionette/driver.js
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -1391,81 +1391,110 @@ GeckoDriver.prototype.switchToWindow = f
 
   // Window IDs are internally handled as numbers, but here it could also be the
   // name of the window.
   let switchTo = parseInt(cmd.parameters.name);
   if (isNaN(switchTo)) {
     switchTo = cmd.parameters.name;
   }
 
-  let byNameOrId = function (name, windowId) {
-    return switchTo === name || switchTo === windowId;
+  let byNameOrId = function (win, windowId) {
+    return switchTo === win.name || switchTo === windowId;
   };
 
-  let found;
-  let winEn = Services.wm.getEnumerator(null);
-  while (winEn.hasMoreElements()) {
-    let win = winEn.getNext();
+  let found = this.findWindow(this.windows, byNameOrId);
+
+  if (found) {
+      yield this.setWindowHandle(found, focus);
+  } else {
+    throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
+  }
+};
+
+/**
+ * Find a specific window according to some filter function.
+ *
+ * @param {Iterable.<Window>} winIterable
+ *     Iterable that emits Windows.
+ * @param {function(Window, number): boolean} filter
+ *     A callback function taking two arguments; the window and
+ *     the outerId of the window, and returning a boolean indicating
+ *     whether the window is the target.
+ *
+ * @return {Object}
+ *     A window handle object containing the window and some
+ *     associated metadata.
+ */
+GeckoDriver.prototype.findWindow = function (winIterable, filter) {
+  for (let win of winIterable) {
     let outerId = getOuterWindowId(win);
     let tabBrowser = browser.getTabBrowser(win);
-
-    if (byNameOrId(win.name, outerId)) {
+    if (filter(win, outerId)) {
       // In case the wanted window is a chrome window, we are done.
-      found = {win: win, outerId: outerId, hasTabBrowser: !!tabBrowser};
-      break;
-
+      return {win: win, outerId: outerId, hasTabBrowser: !!tabBrowser};
     } else if (tabBrowser) {
       // Otherwise check if the chrome window has a tab browser, and that it
       // contains a tab with the wanted window handle.
       for (let i = 0; i < tabBrowser.tabs.length; ++i) {
         let contentBrowser = browser.getBrowserForTab(tabBrowser.tabs[i]);
         let contentWindowId = this.getIdForBrowser(contentBrowser);
 
-        if (byNameOrId(win.name, contentWindowId)) {
-          found = {
+        if (filter(win, contentWindowId)) {
+          return {
             win: win,
             outerId: outerId,
             hasTabBrowser: true,
             tabIndex: i,
           };
-          break;
         }
       }
     }
   }
-
-  if (found) {
-    if (!(found.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;
-
-      if (found.hasTabBrowser) {
-        registerBrowsers = this.registerPromise();
-        browserListening = this.listeningPromise();
-      }
-
-      this.startBrowser(found.win, false /* isNewSession */);
-
-      if (registerBrowsers && browserListening) {
-        yield registerBrowsers;
-        yield browserListening;
-      }
-
-    } else {
-      // Otherwise switch to the known chrome window, and activate the tab
-      // if it's a content browser.
-      this.curBrowser = this.browsers[found.outerId];
-
-      if ("tabIndex" in found) {
-        this.curBrowser.switchToTab(found.tabIndex, found.win, focus);
-      }
+  return null;
+};
+
+/**
+ * Switch the marionette window to a given window. If the browser in
+ * the window is unregistered, registers that browser and waits for
+ * the registration is complete. If |focus| is true then set the focus
+ * on the window.
+ *
+ * @param {Object} winProperties
+ *     Object containing window properties such as returned from
+ *     GeckoDriver#findWindow
+ * @param {boolean=} focus
+ *     A boolean value which determines whether to focus the window.
+ *     Defaults to true.
+ */
+GeckoDriver.prototype.setWindowHandle = function* (winProperties, focus = true) {
+  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;
+
+    if (winProperties.hasTabBrowser) {
+      registerBrowsers = this.registerPromise();
+      browserListening = this.listeningPromise();
     }
+
+    this.startBrowser(winProperties.win, false /* isNewSession */);
+
+    if (registerBrowsers && browserListening) {
+      yield registerBrowsers;
+      yield browserListening;
+    }
+
   } else {
-    throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
+    // Otherwise switch to the known chrome window, and activate the tab
+    // if it's a content browser.
+    this.curBrowser = this.browsers[winProperties.outerId];
+
+    if ("tabIndex" in winProperties) {
+      this.curBrowser.switchToTab(winProperties.tabIndex, winProperties.win, focus);
+    }
   }
 };
 
 GeckoDriver.prototype.getActiveFrame = function (cmd, resp) {
   assert.window(this.getCurrentWindow());
 
   switch (this.context) {
     case Context.CHROME: