summaryrefslogtreecommitdiffstats
path: root/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py')
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
new file mode 100644
index 0000000000..85729cc585
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
@@ -0,0 +1,210 @@
+# 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/.
+
+import sys
+
+from marionette_driver import Wait
+from six import reraise
+
+
+class WindowManagerMixin(object):
+ def setUp(self):
+ super(WindowManagerMixin, self).setUp()
+
+ self.start_window = self.marionette.current_chrome_window_handle
+ self.start_windows = self.marionette.chrome_window_handles
+
+ self.start_tab = self.marionette.current_window_handle
+ self.start_tabs = self.marionette.window_handles
+
+ def tearDown(self):
+ if len(self.marionette.chrome_window_handles) > len(self.start_windows):
+ raise Exception("Not all windows as opened by the test have been closed")
+
+ if len(self.marionette.window_handles) > len(self.start_tabs):
+ raise Exception("Not all tabs as opened by the test have been closed")
+
+ super(WindowManagerMixin, self).tearDown()
+
+ def close_all_tabs(self):
+ current_window_handles = self.marionette.window_handles
+
+ # If the start tab is not present anymore, use the next one of the list
+ if self.start_tab not in current_window_handles:
+ self.start_tab = current_window_handles[0]
+
+ current_window_handles.remove(self.start_tab)
+ for handle in current_window_handles:
+ self.marionette.switch_to_window(handle)
+ self.marionette.close()
+
+ self.marionette.switch_to_window(self.start_tab)
+
+ def close_all_windows(self):
+ current_chrome_window_handles = self.marionette.chrome_window_handles
+
+ # If the start window is not present anymore, use the next one of the list
+ if self.start_window not in current_chrome_window_handles:
+ self.start_window = current_chrome_window_handles[0]
+ current_chrome_window_handles.remove(self.start_window)
+
+ for handle in current_chrome_window_handles:
+ self.marionette.switch_to_window(handle)
+ self.marionette.close_chrome_window()
+
+ self.marionette.switch_to_window(self.start_window)
+
+ def open_tab(self, callback=None, focus=False):
+ current_tabs = self.marionette.window_handles
+
+ try:
+ if callable(callback):
+ callback()
+ else:
+ result = self.marionette.open(type="tab", focus=focus)
+ if result["type"] != "tab":
+ raise Exception(
+ "Newly opened browsing context is of type {} and not tab.".format(
+ result["type"]
+ )
+ )
+ except Exception:
+ exc_cls, exc, tb = sys.exc_info()
+ reraise(
+ exc_cls,
+ exc_cls("Failed to trigger opening a new tab: {}".format(exc)),
+ tb,
+ )
+ else:
+ Wait(self.marionette).until(
+ lambda mn: len(mn.window_handles) == len(current_tabs) + 1,
+ message="No new tab has been opened",
+ )
+
+ [new_tab] = list(set(self.marionette.window_handles) - set(current_tabs))
+
+ return new_tab
+
+ def open_window(self, callback=None, focus=False, private=False):
+ current_windows = self.marionette.chrome_window_handles
+ current_tabs = self.marionette.window_handles
+
+ def loaded(handle):
+ with self.marionette.using_context("chrome"):
+ return self.marionette.execute_script(
+ """
+ const { windowManager } = ChromeUtils.importESModule(
+ "chrome://remote/content/shared/WindowManager.sys.mjs"
+ );
+ const win = windowManager.findWindowByHandle(arguments[0]).win;
+ return win.document.readyState == "complete";
+ """,
+ script_args=[handle],
+ )
+
+ try:
+ if callable(callback):
+ callback(focus)
+ else:
+ result = self.marionette.open(
+ type="window", focus=focus, private=private
+ )
+ if result["type"] != "window":
+ raise Exception(
+ "Newly opened browsing context is of type {} and not window.".format(
+ result["type"]
+ )
+ )
+ except Exception:
+ exc_cls, exc, tb = sys.exc_info()
+ reraise(
+ exc_cls,
+ exc_cls("Failed to trigger opening a new window: {}".format(exc)),
+ tb,
+ )
+ else:
+ Wait(self.marionette).until(
+ lambda mn: len(mn.chrome_window_handles) == len(current_windows) + 1,
+ message="No new window has been opened",
+ )
+
+ [new_window] = list(
+ set(self.marionette.chrome_window_handles) - set(current_windows)
+ )
+
+ # Before continuing ensure the window has been completed loading
+ Wait(self.marionette).until(
+ lambda _: loaded(new_window),
+ message="Window with handle '{}'' did not finish loading".format(
+ new_window
+ ),
+ )
+
+ # Bug 1507771 - Return the correct handle based on the currently selected context
+ # as long as "WebDriver:NewWindow" is not handled separtely in chrome context
+ context = self.marionette._send_message(
+ "Marionette:GetContext", key="value"
+ )
+ if context == "chrome":
+ return new_window
+ elif context == "content":
+ [new_tab] = list(
+ set(self.marionette.window_handles) - set(current_tabs)
+ )
+ return new_tab
+
+ def open_chrome_window(self, url, focus=False):
+ """Open a new chrome window with the specified chrome URL.
+
+ Can be replaced with "WebDriver:NewWindow" once the command
+ supports opening generic chrome windows beside browsers (bug 1507771).
+ """
+
+ def open_with_js(focus):
+ with self.marionette.using_context("chrome"):
+ self.marionette.execute_async_script(
+ """
+ let [url, focus, resolve] = arguments;
+
+ function waitForEvent(target, type, args) {
+ return new Promise(resolve => {
+ let params = Object.assign({once: true}, args);
+ target.addEventListener(type, event => {
+ dump(`** Received DOM event ${event.type} for ${event.target}\n`);
+ resolve();
+ }, params);
+ });
+ }
+
+ function waitForFocus(win) {
+ return Promise.all([
+ waitForEvent(win, "activate"),
+ waitForEvent(win, "focus", {capture: true}),
+ ]);
+ }
+
+ (async function() {
+ // Open a window, wait for it to receive focus
+ let win = window.openDialog(url, null, "chrome,centerscreen");
+ let focused = waitForFocus(win);
+
+ win.focus();
+ await focused;
+
+ // The new window shouldn't get focused. As such set the
+ // focus back to the opening window.
+ if (!focus && Services.focus.activeWindow != window) {
+ let focused = waitForFocus(window);
+ window.focus();
+ await focused;
+ }
+
+ resolve(win.docShell.browsingContext.id);
+ })();
+ """,
+ script_args=(url, focus),
+ )
+
+ with self.marionette.using_context("chrome"):
+ return self.open_window(callback=open_with_js, focus=focus)