mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 23:37:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
|
|
@ -0,0 +1,3 @@
|
|||
# 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/.
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# 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 abc import ABCMeta
|
||||
|
||||
from marionette_driver import By
|
||||
|
||||
from firefox_puppeteer.ui.base import UIBaseLib
|
||||
|
||||
|
||||
class BaseNotification(UIBaseLib):
|
||||
"""Abstract base class for any kind of notification."""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@property
|
||||
def close_button(self):
|
||||
"""Provide access to the close button.
|
||||
|
||||
:returns: The close button.
|
||||
"""
|
||||
return self.element.find_element(By.ANON_ATTRIBUTE,
|
||||
{'anonid': 'closebutton'})
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
"""Provide access to the notification label.
|
||||
|
||||
:returns: The notification label.
|
||||
"""
|
||||
return self.element.get_attribute('label')
|
||||
|
||||
@property
|
||||
def origin(self):
|
||||
"""Provide access to the notification origin.
|
||||
|
||||
:returns: The notification origin.
|
||||
"""
|
||||
return self.element.get_attribute('origin')
|
||||
|
||||
def close(self, force=False):
|
||||
"""Close the notification.
|
||||
|
||||
:param force: Optional, if True force close the notification.
|
||||
Defaults to False.
|
||||
"""
|
||||
if force:
|
||||
self.marionette.execute_script('arguments[0].click()',
|
||||
script_args=[self.close_button])
|
||||
else:
|
||||
self.close_button.click()
|
||||
|
||||
self.window.wait_for_notification(None)
|
||||
|
||||
|
||||
class AddOnInstallBlockedNotification(BaseNotification):
|
||||
"""Add-on install blocked notification."""
|
||||
|
||||
@property
|
||||
def allow_button(self):
|
||||
"""Provide access to the allow button.
|
||||
|
||||
:returns: The allow button.
|
||||
"""
|
||||
return self.element.find_element(
|
||||
By.ANON_ATTRIBUTE, {'anonid': 'button'}).find_element(
|
||||
By.ANON_ATTRIBUTE, {'anonid': 'button'})
|
||||
|
||||
|
||||
class AddOnInstallConfirmationNotification(BaseNotification):
|
||||
"""Add-on install confirmation notification."""
|
||||
|
||||
@property
|
||||
def addon_name(self):
|
||||
"""Provide access to the add-on name.
|
||||
|
||||
:returns: The add-on name.
|
||||
"""
|
||||
label = self.element.find_element(
|
||||
By.CSS_SELECTOR, '#addon-install-confirmation-content label')
|
||||
return label.get_attribute('value')
|
||||
|
||||
def cancel_button(self):
|
||||
"""Provide access to the cancel button.
|
||||
|
||||
:returns: The cancel button.
|
||||
"""
|
||||
return self.element.find_element(
|
||||
By.ID, 'addon-install-confirmation-cancel')
|
||||
|
||||
def install_button(self):
|
||||
"""Provide access to the install button.
|
||||
|
||||
:returns: The install button.
|
||||
"""
|
||||
return self.element.find_element(
|
||||
By.ID, 'addon-install-confirmation-accept')
|
||||
|
||||
|
||||
class AddOnInstallCompleteNotification(BaseNotification):
|
||||
"""Add-on install complete notification."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AddOnInstallFailedNotification(BaseNotification):
|
||||
"""Add-on install failed notification."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AddOnProgressNotification(BaseNotification):
|
||||
"""Add-on progress notification."""
|
||||
|
||||
pass
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
# 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
|
||||
|
||||
import firefox_puppeteer.errors as errors
|
||||
|
||||
from firefox_puppeteer.api.security import Security
|
||||
from firefox_puppeteer.ui.base import UIBaseLib, DOMElement
|
||||
|
||||
|
||||
class TabBar(UIBaseLib):
|
||||
"""Wraps the tabs toolbar DOM element inside a browser window."""
|
||||
|
||||
# Properties for visual elements of the tabs toolbar #
|
||||
|
||||
@property
|
||||
def menupanel(self):
|
||||
"""A :class:`MenuPanel` instance which represents the menu panel
|
||||
at the far right side of the tabs toolbar.
|
||||
|
||||
:returns: :class:`MenuPanel` instance.
|
||||
"""
|
||||
return MenuPanel(self.marionette, self.window)
|
||||
|
||||
@property
|
||||
def newtab_button(self):
|
||||
"""The DOM element which represents the new tab button.
|
||||
|
||||
:returns: Reference to the new tab button.
|
||||
"""
|
||||
return self.toolbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'tabs-newtab-button'})
|
||||
|
||||
@property
|
||||
def tabs(self):
|
||||
"""List of all the :class:`Tab` instances of the current browser window.
|
||||
|
||||
:returns: List of :class:`Tab` instances.
|
||||
"""
|
||||
tabs = self.toolbar.find_elements(By.TAG_NAME, 'tab')
|
||||
|
||||
return [Tab(self.marionette, self.window, tab) for tab in tabs]
|
||||
|
||||
@property
|
||||
def toolbar(self):
|
||||
"""The DOM element which represents the tab toolbar.
|
||||
|
||||
:returns: Reference to the tabs toolbar.
|
||||
"""
|
||||
return self.element
|
||||
|
||||
# Properties for helpers when working with the tabs toolbar #
|
||||
|
||||
@property
|
||||
def selected_index(self):
|
||||
"""The index of the currently selected tab.
|
||||
|
||||
:return: Index of the selected tab.
|
||||
"""
|
||||
return int(self.toolbar.get_property('selectedIndex'))
|
||||
|
||||
@property
|
||||
def selected_tab(self):
|
||||
"""A :class:`Tab` instance of the currently selected tab.
|
||||
|
||||
:returns: :class:`Tab` instance.
|
||||
"""
|
||||
return self.tabs[self.selected_index]
|
||||
|
||||
# Methods for helpers when working with the tabs toolbar #
|
||||
|
||||
def close_all_tabs(self, exceptions=None):
|
||||
"""Forces closing of all open tabs.
|
||||
|
||||
There is an optional `exceptions` list, which can be used to exclude
|
||||
specific tabs from being closed.
|
||||
|
||||
:param exceptions: Optional, list of :class:`Tab` instances not to close.
|
||||
"""
|
||||
# Get handles from tab exceptions, and find those which can be closed
|
||||
for tab in self.tabs:
|
||||
if tab not in exceptions:
|
||||
tab.close(force=True)
|
||||
|
||||
def close_tab(self, tab=None, trigger='menu', force=False):
|
||||
"""Closes the tab by using the specified trigger.
|
||||
|
||||
By default the currently selected tab will be closed. If another :class:`Tab`
|
||||
is specified, that one will be closed instead. Also when the tab is closed, a
|
||||
:func:`switch_to` call is automatically performed, so that the new selected
|
||||
tab becomes active.
|
||||
|
||||
:param tab: Optional, the :class:`Tab` instance to close. Defaults to
|
||||
the currently selected tab.
|
||||
|
||||
:param trigger: Optional, method to close the current tab. This can
|
||||
be a string with one of `menu` or `shortcut`, or a callback which gets triggered
|
||||
with the :class:`Tab` as parameter. Defaults to `menu`.
|
||||
|
||||
:param force: Optional, forces the closing of the window by using the Gecko API.
|
||||
Defaults to `False`.
|
||||
"""
|
||||
tab = tab or self.selected_tab
|
||||
tab.close(trigger, force)
|
||||
|
||||
def open_tab(self, trigger='menu'):
|
||||
"""Opens a new tab in the current browser window.
|
||||
|
||||
If the tab opens in the foreground, a call to :func:`switch_to` will
|
||||
automatically be performed. But if it opens in the background, the current
|
||||
tab will keep its focus.
|
||||
|
||||
:param trigger: Optional, method to open the new tab. This can
|
||||
be a string with one of `menu`, `button` or `shortcut`, or a callback
|
||||
which gets triggered with the current :class:`Tab` as parameter.
|
||||
Defaults to `menu`.
|
||||
|
||||
:returns: :class:`Tab` instance for the opened tab.
|
||||
"""
|
||||
start_handles = self.marionette.window_handles
|
||||
|
||||
# Prepare action which triggers the opening of the browser window
|
||||
if callable(trigger):
|
||||
trigger(self.selected_tab)
|
||||
elif trigger == 'button':
|
||||
self.window.tabbar.newtab_button.click()
|
||||
elif trigger == 'menu':
|
||||
self.window.menubar.select_by_id('file-menu',
|
||||
'menu_newNavigatorTab')
|
||||
elif trigger == 'shortcut':
|
||||
self.window.send_shortcut(self.window.localize_entity('tabCmd.commandkey'),
|
||||
accel=True)
|
||||
# elif - need to add other cases
|
||||
else:
|
||||
raise ValueError('Unknown opening method: "%s"' % trigger)
|
||||
|
||||
# TODO: Needs to be replaced with event handling code (bug 1121705)
|
||||
Wait(self.marionette).until(
|
||||
lambda mn: len(mn.window_handles) == len(start_handles) + 1,
|
||||
message='No new tab has been opened.')
|
||||
|
||||
handles = self.marionette.window_handles
|
||||
[new_handle] = list(set(handles) - set(start_handles))
|
||||
[new_tab] = [tab for tab in self.tabs if tab.handle == new_handle]
|
||||
|
||||
# if the new tab is the currently selected tab, switch to it
|
||||
if new_tab == self.selected_tab:
|
||||
new_tab.switch_to()
|
||||
|
||||
return new_tab
|
||||
|
||||
def switch_to(self, target):
|
||||
"""Switches the context to the specified tab.
|
||||
|
||||
:param target: The tab to switch to. `target` can be an index, a :class:`Tab`
|
||||
instance, or a callback that returns True in the context of the desired tab.
|
||||
|
||||
:returns: Instance of the selected :class:`Tab`.
|
||||
"""
|
||||
start_handle = self.marionette.current_window_handle
|
||||
|
||||
if isinstance(target, int):
|
||||
return self.tabs[target].switch_to()
|
||||
elif isinstance(target, Tab):
|
||||
return target.switch_to()
|
||||
if callable(target):
|
||||
for tab in self.tabs:
|
||||
tab.switch_to()
|
||||
if target(tab):
|
||||
return tab
|
||||
|
||||
self.marionette.switch_to_window(start_handle)
|
||||
raise errors.UnknownTabError("No tab found for '{}'".format(target))
|
||||
|
||||
raise ValueError("The 'target' parameter must either be an index or a callable")
|
||||
|
||||
@staticmethod
|
||||
def get_handle_for_tab(marionette, tab_element):
|
||||
"""Retrieves the marionette handle for the given :class:`Tab` instance.
|
||||
|
||||
:param marionette: An instance of the Marionette client.
|
||||
|
||||
:param tab_element: The DOM element corresponding to a tab inside the tabs toolbar.
|
||||
|
||||
:returns: `handle` of the tab.
|
||||
"""
|
||||
# TODO: This introduces coupling with marionette's window handles
|
||||
# implementation. To avoid this, the capacity to get the XUL
|
||||
# element corresponding to the active window according to
|
||||
# marionette or a similar ability should be added to marionette.
|
||||
handle = marionette.execute_script("""
|
||||
let win = arguments[0].linkedBrowser;
|
||||
if (!win) {
|
||||
return null;
|
||||
}
|
||||
return win.outerWindowID.toString();
|
||||
""", script_args=[tab_element])
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
class Tab(UIBaseLib):
|
||||
"""Wraps a tab DOM element."""
|
||||
|
||||
def __init__(self, marionette, window, element):
|
||||
super(Tab, self).__init__(marionette, window, element)
|
||||
|
||||
self._security = Security(self.marionette)
|
||||
self._handle = None
|
||||
|
||||
# Properties for visual elements of tabs #
|
||||
|
||||
@property
|
||||
def close_button(self):
|
||||
"""The DOM element which represents the tab close button.
|
||||
|
||||
:returns: Reference to the tab close button.
|
||||
"""
|
||||
return self.tab_element.find_element(By.ANON_ATTRIBUTE, {'anonid': 'close-button'})
|
||||
|
||||
@property
|
||||
def tab_element(self):
|
||||
"""The inner tab DOM element.
|
||||
|
||||
:returns: Tab DOM element.
|
||||
"""
|
||||
return self.element
|
||||
|
||||
# Properties for backend values
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
"""Returns the current URL
|
||||
|
||||
:returns: Current URL
|
||||
"""
|
||||
self.switch_to()
|
||||
|
||||
return self.marionette.execute_script("""
|
||||
return arguments[0].linkedBrowser.currentURI.spec;
|
||||
""", script_args=[self.tab_element])
|
||||
|
||||
@property
|
||||
def certificate(self):
|
||||
"""The SSL certificate assiciated with the loaded web page.
|
||||
|
||||
:returns: Certificate details as JSON blob.
|
||||
"""
|
||||
self.switch_to()
|
||||
|
||||
return self._security.get_certificate_for_page(self.tab_element)
|
||||
|
||||
# Properties for helpers when working with tabs #
|
||||
|
||||
@property
|
||||
def handle(self):
|
||||
"""The `handle` of the content window.
|
||||
|
||||
:returns: content window `handle`.
|
||||
"""
|
||||
# If no handle has been set yet, wait until it is available
|
||||
if not self._handle:
|
||||
self._handle = Wait(self.marionette).until(
|
||||
lambda mn: TabBar.get_handle_for_tab(mn, self.element),
|
||||
message='Tab handle could not be found.')
|
||||
|
||||
return self._handle
|
||||
|
||||
@property
|
||||
def selected(self):
|
||||
"""Checks if the tab is selected.
|
||||
|
||||
:return: `True` if the tab is selected.
|
||||
"""
|
||||
return self.marionette.execute_script("""
|
||||
return arguments[0].hasAttribute('selected');
|
||||
""", script_args=[self.tab_element])
|
||||
|
||||
# Methods for helpers when working with tabs #
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.handle == other.handle
|
||||
|
||||
def close(self, trigger='menu', force=False):
|
||||
"""Closes the tab by using the specified trigger.
|
||||
|
||||
When the tab is closed a :func:`switch_to` call is automatically performed, so that
|
||||
the new selected tab becomes active.
|
||||
|
||||
:param trigger: Optional, method in how to close the tab. This can
|
||||
be a string with one of `button`, `menu` or `shortcut`, or a callback which
|
||||
gets triggered with the current :class:`Tab` as parameter. Defaults to `menu`.
|
||||
|
||||
:param force: Optional, forces the closing of the window by using the Gecko API.
|
||||
Defaults to `False`.
|
||||
"""
|
||||
handle = self.handle
|
||||
start_handles = self.marionette.window_handles
|
||||
|
||||
self.switch_to()
|
||||
|
||||
if force:
|
||||
self.marionette.close()
|
||||
elif callable(trigger):
|
||||
trigger(self)
|
||||
elif trigger == 'button':
|
||||
self.close_button.click()
|
||||
elif trigger == 'menu':
|
||||
self.window.menubar.select_by_id('file-menu', 'menu_close')
|
||||
elif trigger == 'shortcut':
|
||||
self.window.send_shortcut(self.window.localize_entity('closeCmd.key'),
|
||||
accel=True)
|
||||
else:
|
||||
raise ValueError('Unknown closing method: "%s"' % trigger)
|
||||
|
||||
Wait(self.marionette).until(
|
||||
lambda _: len(self.window.tabbar.tabs) == len(start_handles) - 1,
|
||||
message='Tab with handle "%s" has not been closed.' % handle)
|
||||
|
||||
# Ensure to switch to the window handle which represents the new selected tab
|
||||
self.window.tabbar.selected_tab.switch_to()
|
||||
|
||||
def select(self):
|
||||
"""Selects the tab and sets the focus to it."""
|
||||
self.tab_element.click()
|
||||
self.switch_to()
|
||||
|
||||
# Bug 1121705: Maybe we have to wait for TabSelect event
|
||||
Wait(self.marionette).until(
|
||||
lambda _: self.selected,
|
||||
message='Tab with handle "%s" could not be selected.' % self.handle)
|
||||
|
||||
def switch_to(self):
|
||||
"""Switches the context of Marionette to this tab.
|
||||
|
||||
Please keep in mind that calling this method will not select the tab.
|
||||
Use the :func:`~Tab.select` method instead.
|
||||
"""
|
||||
self.marionette.switch_to_window(self.handle)
|
||||
|
||||
|
||||
class MenuPanel(UIBaseLib):
|
||||
|
||||
@property
|
||||
def popup(self):
|
||||
"""
|
||||
:returns: The :class:`MenuPanelElement`.
|
||||
"""
|
||||
popup = self.marionette.find_element(By.ID, 'PanelUI-popup')
|
||||
return self.MenuPanelElement(popup)
|
||||
|
||||
class MenuPanelElement(DOMElement):
|
||||
"""Wraps the menu panel."""
|
||||
_buttons = None
|
||||
|
||||
@property
|
||||
def buttons(self):
|
||||
"""
|
||||
:returns: A list of all the clickable buttons in the menu panel.
|
||||
"""
|
||||
if not self._buttons:
|
||||
self._buttons = (self.find_element(By.ID, 'PanelUI-multiView')
|
||||
.find_element(By.ANON_ATTRIBUTE,
|
||||
{'anonid': 'viewContainer'})
|
||||
.find_elements(By.TAG_NAME,
|
||||
'toolbarbutton'))
|
||||
return self._buttons
|
||||
|
||||
def click(self, target=None):
|
||||
"""
|
||||
Overrides HTMLElement.click to provide a target to click.
|
||||
|
||||
:param target: The label associated with the button to click on,
|
||||
e.g., `New Private Window`.
|
||||
"""
|
||||
if not target:
|
||||
return DOMElement.click(self)
|
||||
|
||||
for button in self.buttons:
|
||||
if button.get_attribute('label') == target:
|
||||
return button.click()
|
||||
raise NoSuchElementException('Could not find "{}"" in the '
|
||||
'menu panel UI'.format(target))
|
||||
|
|
@ -0,0 +1,641 @@
|
|||
# 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, keys, Wait
|
||||
|
||||
from firefox_puppeteer.ui.base import UIBaseLib
|
||||
|
||||
|
||||
class NavBar(UIBaseLib):
|
||||
"""Provides access to the DOM elements contained in the
|
||||
navigation bar as well as the location bar."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(NavBar, self).__init__(*args, **kwargs)
|
||||
|
||||
self._locationbar = None
|
||||
|
||||
@property
|
||||
def back_button(self):
|
||||
"""Provides access to the DOM element back button in the navbar.
|
||||
|
||||
:returns: Reference to the back button.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'back-button')
|
||||
|
||||
@property
|
||||
def forward_button(self):
|
||||
"""Provides access to the DOM element forward button in the navbar.
|
||||
|
||||
:returns: Reference to the forward button.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'forward-button')
|
||||
|
||||
@property
|
||||
def home_button(self):
|
||||
"""Provides access to the DOM element home button in the navbar.
|
||||
|
||||
:returns: Reference to the home button element
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'home-button')
|
||||
|
||||
@property
|
||||
def locationbar(self):
|
||||
"""Provides access to the DOM elements contained in the
|
||||
locationbar.
|
||||
|
||||
See the :class:`LocationBar` reference.
|
||||
"""
|
||||
if not self._locationbar:
|
||||
urlbar = self.marionette.find_element(By.ID, 'urlbar')
|
||||
self._locationbar = LocationBar(self.marionette, self.window, urlbar)
|
||||
|
||||
return self._locationbar
|
||||
|
||||
@property
|
||||
def menu_button(self):
|
||||
"""Provides access to the DOM element menu button in the navbar.
|
||||
|
||||
:returns: Reference to the menu button element.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'PanelUI-menu-button')
|
||||
|
||||
@property
|
||||
def toolbar(self):
|
||||
"""The DOM element which represents the navigation toolbar.
|
||||
|
||||
:returns: Reference to the navigation toolbar.
|
||||
"""
|
||||
return self.element
|
||||
|
||||
|
||||
class LocationBar(UIBaseLib):
|
||||
"""Provides access to and methods for the DOM elements contained in the
|
||||
locationbar (the text area of the ui that typically displays the current url)."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LocationBar, self).__init__(*args, **kwargs)
|
||||
|
||||
self._autocomplete_results = None
|
||||
self._identity_popup = None
|
||||
|
||||
@property
|
||||
def autocomplete_results(self):
|
||||
"""Provides access to and methods for the location bar
|
||||
autocomplete results.
|
||||
|
||||
See the :class:`AutocompleteResults` reference."""
|
||||
if not self._autocomplete_results:
|
||||
popup = self.marionette.find_element(By.ID, 'PopupAutoCompleteRichResult')
|
||||
self._autocomplete_results = AutocompleteResults(self.marionette,
|
||||
self.window, popup)
|
||||
|
||||
return self._autocomplete_results
|
||||
|
||||
def clear(self):
|
||||
"""Clears the contents of the url bar (via the DELETE shortcut)."""
|
||||
self.focus('shortcut')
|
||||
self.urlbar.send_keys(keys.Keys.DELETE)
|
||||
Wait(self.marionette).until(
|
||||
lambda _: self.value == '',
|
||||
message='Contents of location bar could not be cleared.')
|
||||
|
||||
def close_context_menu(self):
|
||||
"""Closes the Location Bar context menu by a key event."""
|
||||
# TODO: This method should be implemented via the menu API.
|
||||
self.contextmenu.send_keys(keys.Keys.ESCAPE)
|
||||
|
||||
@property
|
||||
def connection_icon(self):
|
||||
""" Provides access to the urlbar connection icon.
|
||||
|
||||
:returns: Reference to the connection icon element.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'connection-icon')
|
||||
|
||||
@property
|
||||
def contextmenu(self):
|
||||
"""Provides access to the urlbar context menu.
|
||||
|
||||
:returns: Reference to the urlbar context menu.
|
||||
"""
|
||||
# TODO: This method should be implemented via the menu API.
|
||||
parent = self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'textbox-input-box'})
|
||||
return parent.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input-box-contextmenu'})
|
||||
|
||||
@property
|
||||
def focused(self):
|
||||
"""Checks the focus state of the location bar.
|
||||
|
||||
:returns: `True` if focused, otherwise `False`
|
||||
"""
|
||||
return self.urlbar.get_attribute('focused') == 'true'
|
||||
|
||||
@property
|
||||
def identity_icon(self):
|
||||
""" Provides access to the urlbar identity icon.
|
||||
|
||||
:returns: Reference to the identity icon element.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'identity-icon')
|
||||
|
||||
def focus(self, event='click'):
|
||||
"""Focus the location bar according to the provided event.
|
||||
|
||||
:param eventt: The event to synthesize in order to focus the urlbar
|
||||
(one of `click` or `shortcut`).
|
||||
"""
|
||||
if event == 'click':
|
||||
self.urlbar.click()
|
||||
elif event == 'shortcut':
|
||||
cmd_key = self.window.localize_entity('openCmd.commandkey')
|
||||
self.window.send_shortcut(cmd_key, accel=True)
|
||||
else:
|
||||
raise ValueError("An unknown event type was passed: %s" % event)
|
||||
|
||||
Wait(self.marionette).until(
|
||||
lambda _: self.focused,
|
||||
message='Location bar has not be focused.')
|
||||
|
||||
def get_contextmenu_entry(self, action):
|
||||
"""Retrieves the urlbar context menu entry corresponding
|
||||
to the given action.
|
||||
|
||||
:param action: The action corresponding to the retrieved value.
|
||||
:returns: Reference to the urlbar contextmenu entry.
|
||||
"""
|
||||
# TODO: This method should be implemented via the menu API.
|
||||
entries = self.contextmenu.find_elements(By.CSS_SELECTOR, 'menuitem')
|
||||
filter_on = 'cmd_%s' % action
|
||||
found = [e for e in entries if e.get_attribute('cmd') == filter_on]
|
||||
return found[0] if len(found) else None
|
||||
|
||||
@property
|
||||
def history_drop_marker(self):
|
||||
"""Provides access to the history drop marker.
|
||||
|
||||
:returns: Reference to the history drop marker.
|
||||
"""
|
||||
return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'historydropmarker'})
|
||||
|
||||
@property
|
||||
def identity_box(self):
|
||||
"""The DOM element which represents the identity box.
|
||||
|
||||
:returns: Reference to the identity box.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'identity-box')
|
||||
|
||||
@property
|
||||
def identity_country_label(self):
|
||||
"""The DOM element which represents the identity icon country label.
|
||||
|
||||
:returns: Reference to the identity icon country label.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'identity-icon-country-label')
|
||||
|
||||
@property
|
||||
def identity_organization_label(self):
|
||||
"""The DOM element which represents the identity icon label.
|
||||
|
||||
:returns: Reference to the identity icon label.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'identity-icon-label')
|
||||
|
||||
@property
|
||||
def identity_popup(self):
|
||||
"""Provides utility members for accessing and manipulating the
|
||||
identity popup.
|
||||
|
||||
See the :class:`IdentityPopup` reference.
|
||||
"""
|
||||
if not self._identity_popup:
|
||||
popup = self.marionette.find_element(By.ID, 'identity-popup')
|
||||
self._identity_popup = IdentityPopup(self.marionette,
|
||||
self.window, popup)
|
||||
|
||||
return self._identity_popup
|
||||
|
||||
def load_url(self, url):
|
||||
"""Load the specified url in the location bar by synthesized
|
||||
keystrokes.
|
||||
|
||||
:param url: The url to load.
|
||||
"""
|
||||
self.clear()
|
||||
self.focus('shortcut')
|
||||
self.urlbar.send_keys(url + keys.Keys.ENTER)
|
||||
|
||||
@property
|
||||
def notification_popup(self):
|
||||
"""Provides access to the DOM element notification popup.
|
||||
|
||||
:returns: Reference to the notification popup.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, "notification-popup")
|
||||
|
||||
def open_identity_popup(self):
|
||||
"""Open the identity popup."""
|
||||
self.identity_box.click()
|
||||
Wait(self.marionette).until(
|
||||
lambda _: self.identity_popup.is_open,
|
||||
message='Identity popup has not been opened.')
|
||||
|
||||
@property
|
||||
def reload_button(self):
|
||||
"""Provides access to the DOM element reload button.
|
||||
|
||||
:returns: Reference to the reload button.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'urlbar-reload-button')
|
||||
|
||||
def reload_url(self, trigger='button', force=False):
|
||||
"""Reload the currently open page.
|
||||
|
||||
:param trigger: The event type to use to cause the reload (one of
|
||||
`shortcut`, `shortcut2`, or `button`).
|
||||
:param force: Whether to cause a forced reload.
|
||||
"""
|
||||
# TODO: The force parameter is ignored for the moment. Use
|
||||
# mouse event modifiers or actions when they're ready.
|
||||
# Bug 1097705 tracks this feature in marionette.
|
||||
if trigger == 'button':
|
||||
self.reload_button.click()
|
||||
elif trigger == 'shortcut':
|
||||
cmd_key = self.window.localize_entity('reloadCmd.commandkey')
|
||||
self.window.send_shortcut(cmd_key)
|
||||
elif trigger == 'shortcut2':
|
||||
self.window.send_shortcut(keys.Keys.F5)
|
||||
|
||||
@property
|
||||
def stop_button(self):
|
||||
"""Provides access to the DOM element stop button.
|
||||
|
||||
:returns: Reference to the stop button.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'urlbar-stop-button')
|
||||
|
||||
@property
|
||||
def urlbar(self):
|
||||
"""Provides access to the DOM element urlbar.
|
||||
|
||||
:returns: Reference to the url bar.
|
||||
"""
|
||||
return self.marionette.find_element(By.ID, 'urlbar')
|
||||
|
||||
@property
|
||||
def urlbar_input(self):
|
||||
"""Provides access to the urlbar input element.
|
||||
|
||||
:returns: Reference to the urlbar input.
|
||||
"""
|
||||
return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input'})
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Provides access to the currently displayed value of the urlbar.
|
||||
|
||||
:returns: The urlbar value.
|
||||
"""
|
||||
return self.urlbar.get_property('value')
|
||||
|
||||
|
||||
class AutocompleteResults(UIBaseLib):
|
||||
"""Wraps DOM elements and methods for interacting with autocomplete results."""
|
||||
|
||||
def close(self, force=False):
|
||||
"""Closes the urlbar autocomplete popup.
|
||||
|
||||
:param force: If true, the popup is closed by its own hide function,
|
||||
otherwise a key event is sent to close the popup.
|
||||
"""
|
||||
if not self.is_open:
|
||||
return
|
||||
|
||||
if force:
|
||||
self.marionette.execute_script("""
|
||||
arguments[0].hidePopup();
|
||||
""", script_args=[self.element])
|
||||
else:
|
||||
self.element.send_keys(keys.Keys.ESCAPE)
|
||||
|
||||
Wait(self.marionette).until(
|
||||
lambda _: not self.is_open,
|
||||
message='Autocomplete popup has not been closed.')
|
||||
|
||||
def get_matching_text(self, result, match_type):
|
||||
"""Returns an array of strings of the matching text within an autocomplete
|
||||
result in the urlbar.
|
||||
|
||||
:param result: The result to inspect for matches.
|
||||
:param match_type: The type of match to search for (one of `title` or `url`).
|
||||
"""
|
||||
|
||||
if match_type not in ('title', 'url'):
|
||||
raise ValueError('match_type provided must be one of'
|
||||
'"title" or "url", not %s' % match_type)
|
||||
|
||||
# Search for nodes of the given type with emphasized text
|
||||
emphasized_nodes = result.find_elements(
|
||||
By.ANON_ATTRIBUTE,
|
||||
{'class': 'ac-emphasize-text ac-emphasize-text-%s' % match_type}
|
||||
)
|
||||
|
||||
return [node.get_property('textContent') for node in emphasized_nodes]
|
||||
|
||||
@property
|
||||
def visible_results(self):
|
||||
"""Supplies the list of visible autocomplete result nodes.
|
||||
|
||||
:returns: The list of visible results.
|
||||
"""
|
||||
match_count = self.element.get_property('_matchCount')
|
||||
|
||||
return self.marionette.execute_script("""
|
||||
let rv = [];
|
||||
let node = arguments[0];
|
||||
let count = arguments[1];
|
||||
|
||||
for (let i = 0; i < count; ++i) {
|
||||
rv.push(node.getItemAtIndex(i));
|
||||
}
|
||||
|
||||
return rv;
|
||||
""", script_args=[self.results, match_count])
|
||||
|
||||
@property
|
||||
def is_open(self):
|
||||
"""Returns whether this popup is currently open.
|
||||
|
||||
:returns: True when the popup is open, otherwise false.
|
||||
"""
|
||||
return self.element.get_property('state') == 'open'
|
||||
|
||||
@property
|
||||
def is_complete(self):
|
||||
"""Returns when this popup is open and autocomplete results are complete.
|
||||
|
||||
:returns: True, when autocomplete results have been populated.
|
||||
"""
|
||||
return self.marionette.execute_script("""
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let win = Services.focus.activeWindow;
|
||||
if (win) {
|
||||
return win.gURLBar.controller.searchStatus >=
|
||||
Components.interfaces.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
|
||||
}
|
||||
|
||||
return null;
|
||||
""")
|
||||
|
||||
@property
|
||||
def results(self):
|
||||
"""
|
||||
:returns: The autocomplete result container node.
|
||||
"""
|
||||
return self.element.find_element(By.ANON_ATTRIBUTE,
|
||||
{'anonid': 'richlistbox'})
|
||||
|
||||
@property
|
||||
def selected_index(self):
|
||||
"""Provides the index of the selected item in the autocomplete list.
|
||||
|
||||
:returns: The index.
|
||||
"""
|
||||
return self.results.get_property('selectedIndex')
|
||||
|
||||
|
||||
class IdentityPopup(UIBaseLib):
|
||||
"""Wraps DOM elements and methods for interacting with the identity popup."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IdentityPopup, self).__init__(*args, **kwargs)
|
||||
|
||||
self._view = None
|
||||
|
||||
@property
|
||||
def is_open(self):
|
||||
"""Returns whether this popup is currently open.
|
||||
|
||||
:returns: True when the popup is open, otherwise false.
|
||||
"""
|
||||
return self.element.get_property('state') == 'open'
|
||||
|
||||
def close(self, force=False):
|
||||
"""Closes the identity popup by hitting the escape key.
|
||||
|
||||
:param force: Optional, If `True` force close the popup.
|
||||
Defaults to `False`
|
||||
"""
|
||||
if not self.is_open:
|
||||
return
|
||||
|
||||
if force:
|
||||
self.marionette.execute_script("""
|
||||
arguments[0].hidePopup();
|
||||
""", script_args=[self.element])
|
||||
else:
|
||||
self.element.send_keys(keys.Keys.ESCAPE)
|
||||
|
||||
Wait(self.marionette).until(
|
||||
lambda _: not self.is_open,
|
||||
message='Identity popup has not been closed.')
|
||||
|
||||
@property
|
||||
def view(self):
|
||||
"""Provides utility members for accessing and manipulating the
|
||||
identity popup's multi view.
|
||||
|
||||
See the :class:`IdentityPopupMultiView` reference.
|
||||
"""
|
||||
if not self._view:
|
||||
view = self.marionette.find_element(By.ID, 'identity-popup-multiView')
|
||||
self._view = IdentityPopupMultiView(self.marionette, self.window, view)
|
||||
|
||||
return self._view
|
||||
|
||||
|
||||
class IdentityPopupMultiView(UIBaseLib):
|
||||
|
||||
def _create_view_for_id(self, view_id):
|
||||
"""Creates an instance of :class:`IdentityPopupView` for the specified view id.
|
||||
|
||||
:param view_id: The ID of the view to create an instance of.
|
||||
|
||||
:returns: :class:`IdentityPopupView` instance
|
||||
"""
|
||||
mapping = {'identity-popup-mainView': IdentityPopupMainView,
|
||||
'identity-popup-securityView': IdentityPopupSecurityView,
|
||||
}
|
||||
|
||||
view = self.marionette.find_element(By.ID, view_id)
|
||||
return mapping.get(view_id, IdentityPopupView)(self.marionette, self.window, view)
|
||||
|
||||
@property
|
||||
def main(self):
|
||||
"""The DOM element which represents the main view.
|
||||
|
||||
:returns: Reference to the main view.
|
||||
"""
|
||||
return self._create_view_for_id('identity-popup-mainView')
|
||||
|
||||
@property
|
||||
def security(self):
|
||||
"""The DOM element which represents the security view.
|
||||
|
||||
:returns: Reference to the security view.
|
||||
"""
|
||||
return self._create_view_for_id('identity-popup-securityView')
|
||||
|
||||
|
||||
class IdentityPopupView(UIBaseLib):
|
||||
|
||||
@property
|
||||
def selected(self):
|
||||
"""Checks if the view is selected.
|
||||
|
||||
:return: `True` if the view is selected.
|
||||
"""
|
||||
return self.element.get_attribute('current') == 'true'
|
||||
|
||||
|
||||
class IdentityPopupMainView(IdentityPopupView):
|
||||
|
||||
@property
|
||||
def selected(self):
|
||||
"""Checks if the view is selected.
|
||||
|
||||
:return: `True` if the view is selected.
|
||||
"""
|
||||
return self.marionette.execute_script("""
|
||||
return arguments[0].panelMultiView.getAttribute('viewtype') == 'main';
|
||||
""", script_args=[self.element])
|
||||
|
||||
@property
|
||||
def expander(self):
|
||||
"""The DOM element which represents the expander button for the security content.
|
||||
|
||||
:returns: Reference to the identity popup expander button.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-expander')
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""The DOM element which represents the identity-popup content host.
|
||||
|
||||
:returns: Reference to the identity-popup content host.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
|
||||
|
||||
@property
|
||||
def insecure_connection_label(self):
|
||||
"""The DOM element which represents the identity popup insecure connection label.
|
||||
|
||||
:returns: Reference to the identity-popup insecure connection label.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
|
||||
|
||||
@property
|
||||
def internal_connection_label(self):
|
||||
"""The DOM element which represents the identity popup internal connection label.
|
||||
|
||||
:returns: Reference to the identity-popup internal connection label.
|
||||
"""
|
||||
return self.element.find_element(By.CSS_SELECTOR, 'description[when-connection=chrome]')
|
||||
|
||||
@property
|
||||
def permissions(self):
|
||||
"""The DOM element which represents the identity-popup permissions content.
|
||||
|
||||
:returns: Reference to the identity-popup permissions.
|
||||
"""
|
||||
return self.element.find_element(By.ID, 'identity-popup-permissions-content')
|
||||
|
||||
@property
|
||||
def secure_connection_label(self):
|
||||
"""The DOM element which represents the identity popup secure connection label.
|
||||
|
||||
:returns: Reference to the identity-popup secure connection label.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
|
||||
|
||||
|
||||
class IdentityPopupSecurityView(IdentityPopupView):
|
||||
|
||||
@property
|
||||
def disable_mixed_content_blocking_button(self):
|
||||
"""The DOM element which represents the disable mixed content blocking button.
|
||||
|
||||
:returns: Reference to the disable mixed content blocking button.
|
||||
"""
|
||||
return self.element.find_element(By.CSS_SELECTOR,
|
||||
'button[when-mixedcontent=active-blocked]')
|
||||
|
||||
@property
|
||||
def enable_mixed_content_blocking_button(self):
|
||||
"""The DOM element which represents the enable mixed content blocking button.
|
||||
|
||||
:returns: Reference to the enable mixed content blocking button.
|
||||
"""
|
||||
return self.element.find_element(By.CSS_SELECTOR,
|
||||
'button[when-mixedcontent=active-loaded]')
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""The DOM element which represents the identity-popup content host.
|
||||
|
||||
:returns: Reference to the identity-popup content host.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
|
||||
|
||||
@property
|
||||
def insecure_connection_label(self):
|
||||
"""The DOM element which represents the identity popup insecure connection label.
|
||||
|
||||
:returns: Reference to the identity-popup insecure connection label.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
|
||||
|
||||
@property
|
||||
def more_info_button(self):
|
||||
"""The DOM element which represents the identity-popup more info button.
|
||||
|
||||
:returns: Reference to the identity-popup more info button.
|
||||
"""
|
||||
label = self.window.localize_entity('identity.moreInfoLinkText2')
|
||||
|
||||
return self.element.find_element(By.CSS_SELECTOR, u'button[label="{}"]'.format(label))
|
||||
|
||||
@property
|
||||
def owner(self):
|
||||
"""The DOM element which represents the identity-popup content owner.
|
||||
|
||||
:returns: Reference to the identity-popup content owner.
|
||||
"""
|
||||
return self.element.find_element(By.ID, 'identity-popup-content-owner')
|
||||
|
||||
@property
|
||||
def owner_location(self):
|
||||
"""The DOM element which represents the identity-popup content supplemental.
|
||||
|
||||
:returns: Reference to the identity-popup content supplemental.
|
||||
"""
|
||||
return self.element.find_element(By.ID, 'identity-popup-content-supplemental')
|
||||
|
||||
@property
|
||||
def secure_connection_label(self):
|
||||
"""The DOM element which represents the identity popup secure connection label.
|
||||
|
||||
:returns: Reference to the identity-popup secure connection label.
|
||||
"""
|
||||
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
|
||||
|
||||
@property
|
||||
def verifier(self):
|
||||
"""The DOM element which represents the identity-popup content verifier.
|
||||
|
||||
:returns: Reference to the identity-popup content verifier.
|
||||
"""
|
||||
return self.element.find_element(By.ID, 'identity-popup-content-verifier')
|
||||
|
|
@ -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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue