diff options
Diffstat (limited to 'testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py')
-rw-r--r-- | testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py new file mode 100644 index 000000000..728a2fd20 --- /dev/null +++ b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py @@ -0,0 +1,260 @@ +# 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 import By, Wait +from marionette_driver.errors import NoSuchElementException + +from firefox_puppeteer.ui.about_window.window import AboutWindow +from firefox_puppeteer.ui.browser.notifications import ( + AddOnInstallBlockedNotification, + AddOnInstallConfirmationNotification, + AddOnInstallCompleteNotification, + AddOnInstallFailedNotification, + AddOnProgressNotification, + BaseNotification) +from firefox_puppeteer.ui.browser.tabbar import TabBar +from firefox_puppeteer.ui.browser.toolbars import NavBar +from firefox_puppeteer.ui.pageinfo.window import PageInfoWindow +from firefox_puppeteer.ui.windows import BaseWindow, Windows + + +class BrowserWindow(BaseWindow): + """Representation of a browser window.""" + + window_type = 'navigator:browser' + + dtds = [ + 'chrome://branding/locale/brand.dtd', + 'chrome://browser/locale/aboutPrivateBrowsing.dtd', + 'chrome://browser/locale/browser.dtd', + 'chrome://browser/locale/netError.dtd', + ] + + properties = [ + 'chrome://branding/locale/brand.properties', + 'chrome://branding/locale/browserconfig.properties', + 'chrome://browser/locale/browser.properties', + 'chrome://browser/locale/preferences/preferences.properties', + 'chrome://global/locale/browser.properties', + ] + + def __init__(self, *args, **kwargs): + super(BrowserWindow, self).__init__(*args, **kwargs) + + self._navbar = None + self._tabbar = None + + @property + def default_homepage(self): + """The default homepage as used by the current locale. + + :returns: The default homepage for the current locale. + """ + return self.marionette.get_pref('browser.startup.homepage', + value_type='nsIPrefLocalizedString') + + @property + def is_private(self): + """Returns True if this is a Private Browsing window.""" + self.switch_to() + + with self.marionette.using_context('chrome'): + return self.marionette.execute_script(""" + Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); + + let chromeWindow = arguments[0].ownerDocument.defaultView; + return PrivateBrowsingUtils.isWindowPrivate(chromeWindow); + """, script_args=[self.window_element]) + + @property + def navbar(self): + """Provides access to the navigation bar. This is the toolbar containing + the back, forward and home buttons. It also contains the location bar. + + See the :class:`~ui.browser.toolbars.NavBar` reference. + """ + self.switch_to() + + if not self._navbar: + navbar = self.window_element.find_element(By.ID, 'nav-bar') + self._navbar = NavBar(self.marionette, self, navbar) + + return self._navbar + + @property + def notification(self): + """Provides access to the currently displayed notification.""" + + notifications_map = { + 'addon-install-blocked-notification': AddOnInstallBlockedNotification, + 'addon-install-confirmation-notification': AddOnInstallConfirmationNotification, + 'addon-install-complete-notification': AddOnInstallCompleteNotification, + 'addon-install-failed-notification': AddOnInstallFailedNotification, + 'addon-progress-notification': AddOnProgressNotification, + } + + try: + notification = self.window_element.find_element( + By.CSS_SELECTOR, '#notification-popup popupnotification') + + notification_id = notification.get_attribute('id') + return notifications_map.get(notification_id, BaseNotification)( + self.marionette, self, notification) + + except NoSuchElementException: + return None # no notification is displayed + + def wait_for_notification(self, notification_class=BaseNotification, + timeout=5): + """Waits for the specified notification to be displayed. + + :param notification_class: Optional, the notification class to wait for. + If `None` is specified it will wait for any notification to be closed. + Defaults to `BaseNotification`. + :param timeout: Optional, how long to wait for the expected notification. + Defaults to 5 seconds. + """ + wait = Wait(self.marionette, timeout=timeout) + + if notification_class: + if notification_class is BaseNotification: + message = 'No notification was shown.' + else: + message = '{0} was not shown.'.format(notification_class.__name__) + wait.until( + lambda _: isinstance(self.notification, notification_class), + message=message) + else: + message = 'Unexpected notification shown.' + wait.until( + lambda _: self.notification is None, + message='Unexpected notification shown.') + + @property + def tabbar(self): + """Provides access to the tab bar. + + See the :class:`~ui.browser.tabbar.TabBar` reference. + """ + self.switch_to() + + if not self._tabbar: + tabbrowser = self.window_element.find_element(By.ID, 'tabbrowser-tabs') + self._tabbar = TabBar(self.marionette, self, tabbrowser) + + return self._tabbar + + def close(self, trigger='menu', force=False): + """Closes the current browser window by using the specified trigger. + + :param trigger: Optional, method to close the current browser window. This can + be a string with one of `menu` or `shortcut`, or a callback which gets triggered + with the current :class:`BrowserWindow` as parameter. Defaults to `menu`. + + :param force: Optional, forces the closing of the window by using the Gecko API. + Defaults to `False`. + """ + def callback(win): + # Prepare action which triggers the opening of the browser window + if callable(trigger): + trigger(win) + elif trigger == 'menu': + self.menubar.select_by_id('file-menu', 'menu_closeWindow') + elif trigger == 'shortcut': + win.send_shortcut(win.localize_entity('closeCmd.key'), + accel=True, shift=True) + else: + raise ValueError('Unknown closing method: "%s"' % trigger) + + BaseWindow.close(self, callback, force) + + def get_final_url(self, url): + """Loads the page at `url` and returns the resulting url. + + This function enables testing redirects. + + :param url: The url to test. + :returns: The resulting loaded url. + """ + with self.marionette.using_context('content'): + self.marionette.navigate(url) + return self.marionette.get_url() + + def open_browser(self, trigger='menu', is_private=False): + """Opens a new browser window by using the specified trigger. + + :param trigger: Optional, method in how to open the new browser window. This can + be a string with one of `menu` or `shortcut`, or a callback which gets triggered + with the current :class:`BrowserWindow` as parameter. Defaults to `menu`. + + :param is_private: Optional, if True the new window will be a private browsing one. + + :returns: :class:`BrowserWindow` instance for the new browser window. + """ + def callback(win): + # Prepare action which triggers the opening of the browser window + if callable(trigger): + trigger(win) + elif trigger == 'menu': + menu_id = 'menu_newPrivateWindow' if is_private else 'menu_newNavigator' + self.menubar.select_by_id('file-menu', menu_id) + elif trigger == 'shortcut': + cmd_key = 'privateBrowsingCmd.commandkey' if is_private else 'newNavigatorCmd.key' + win.send_shortcut(win.localize_entity(cmd_key), + accel=True, shift=is_private) + else: + raise ValueError('Unknown opening method: "%s"' % trigger) + + return BaseWindow.open_window(self, callback, BrowserWindow) + + def open_about_window(self, trigger='menu'): + """Opens the about window by using the specified trigger. + + :param trigger: Optional, method in how to open the new browser window. This can + either the string `menu` or a callback which gets triggered + with the current :class:`BrowserWindow` as parameter. Defaults to `menu`. + + :returns: :class:`AboutWindow` instance of the opened window. + """ + def callback(win): + # Prepare action which triggers the opening of the browser window + if callable(trigger): + trigger(win) + elif trigger == 'menu': + self.menubar.select_by_id('helpMenu', 'aboutName') + else: + raise ValueError('Unknown opening method: "%s"' % trigger) + + return BaseWindow.open_window(self, callback, AboutWindow) + + def open_page_info_window(self, trigger='menu'): + """Opens the page info window by using the specified trigger. + + :param trigger: Optional, method in how to open the new browser window. This can + be a string with one of `menu` or `shortcut`, or a callback which gets triggered + with the current :class:`BrowserWindow` as parameter. Defaults to `menu`. + + :returns: :class:`PageInfoWindow` instance of the opened window. + """ + def callback(win): + # Prepare action which triggers the opening of the browser window + if callable(trigger): + trigger(win) + elif trigger == 'menu': + self.menubar.select_by_id('tools-menu', 'menu_pageInfo') + elif trigger == 'shortcut': + if win.marionette.session_capabilities['platformName'] == 'windows_nt': + raise ValueError('Page info shortcut not available on Windows.') + win.send_shortcut(win.localize_entity('pageInfoCmd.commandkey'), + accel=True) + elif trigger == 'context_menu': + # TODO: Add once we can do right clicks + pass + else: + raise ValueError('Unknown opening method: "%s"' % trigger) + + return BaseWindow.open_window(self, callback, PageInfoWindow) + + +Windows.register_window(BrowserWindow.window_type, BrowserWindow) |