From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../runner/mixins/window_manager.py | 210 +++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py (limited to 'testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py') 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) -- cgit v1.2.3