Dactyloidae/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py

260 lines
10 KiB
Python
Raw Normal View History

# 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)