--- a/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
@@ -13,17 +13,17 @@ from marionette_driver import Wait
from marionette_driver.errors import NoSuchWindowException
from firefox_puppeteer.api.prefs import Preferences
from firefox_puppeteer.api.software_update import SoftwareUpdate
from firefox_puppeteer.testcases import BaseFirefoxTestCase
from firefox_puppeteer.ui.update_wizard import UpdateWizardDialog
-class FirefoxTestCase(BaseFirefoxTestCase, MarionetteTestCase):
+class FirefoxTestCase(BaseFirefoxTestCase):
""" Integrate MarionetteTestCase with BaseFirefoxTestCase by reordering MRO """
pass
class UpdateTestCase(FirefoxTestCase):
TIMEOUT_UPDATE_APPLY = 300
TIMEOUT_UPDATE_CHECK = 30
@@ -50,17 +50,17 @@ class UpdateTestCase(FirefoxTestCase):
self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
self.default_mar_channels = None
self.updates = []
def setUp(self, is_fallback=False):
super(UpdateTestCase, self).setUp()
- self.software_update = SoftwareUpdate(lambda: self.marionette)
+ self.software_update = SoftwareUpdate(self.marionette)
self.download_duration = None
# Bug 604364 - Preparation to test multiple update steps
self.current_update_index = 0
# Ensure that there exists no already partially downloaded update
self.remove_downloaded_update()
@@ -224,17 +224,17 @@ class UpdateTestCase(FirefoxTestCase):
:param timeout: How long to wait for the download to finish. Optional, default to 360s.
"""
def download_via_update_wizard(dialog):
""" Download the update via the old update wizard dialog.
:param dialog: Instance of :class:`UpdateWizardDialog`.
"""
- prefs = Preferences(lambda: self.marionette)
+ prefs = Preferences(self.marionette)
prefs.set_pref(self.PREF_APP_UPDATE_ALTWINDOWTYPE, dialog.window_type)
try:
# If updates have already been found, proceed to download
if dialog.wizard.selected_panel in [dialog.wizard.updates_found_basic,
dialog.wizard.error_patching,
]:
dialog.select_next_page()
--- a/testing/firefox-ui/tests/puppeteer/test_l10n.py
+++ b/testing/firefox-ui/tests/puppeteer/test_l10n.py
@@ -8,17 +8,17 @@ from marionette_driver.errors import Mar
from firefox_puppeteer.api.l10n import L10n
from firefox_ui_harness.testcases import FirefoxTestCase
class TestL10n(FirefoxTestCase):
def setUp(self):
FirefoxTestCase.setUp(self)
- self.l10n = L10n(lambda: self.marionette)
+ self.l10n = L10n(self.marionette)
def tearDown(self):
FirefoxTestCase.tearDown(self)
def test_dtd_entity_chrome(self):
dtds = ['chrome://global/locale/about.dtd',
'chrome://browser/locale/baseMenuOverlay.dtd']
--- a/testing/firefox-ui/tests/puppeteer/test_software_update.py
+++ b/testing/firefox-ui/tests/puppeteer/test_software_update.py
@@ -8,17 +8,17 @@ from firefox_ui_harness.testcases import
from firefox_puppeteer.api.software_update import SoftwareUpdate
class TestSoftwareUpdate(FirefoxTestCase):
def setUp(self):
FirefoxTestCase.setUp(self)
- self.software_update = SoftwareUpdate(lambda: self.marionette)
+ self.software_update = SoftwareUpdate(self.marionette)
self.saved_mar_channels = self.software_update.mar_channels.channels
self.software_update.mar_channels.channels = set(['expected', 'channels'])
def tearDown(self):
try:
self.software_update.mar_channels.channels = self.saved_mar_channels
finally:
@@ -67,17 +67,17 @@ class TestSoftwareUpdate(FirefoxTestCase
def test_staging_directory(self):
self.assertTrue(self.software_update.staging_directory)
class TestUpdateChannel(FirefoxTestCase):
def setUp(self):
FirefoxTestCase.setUp(self)
- self.software_update = SoftwareUpdate(lambda: self.marionette)
+ self.software_update = SoftwareUpdate(self.marionette)
self.saved_channel = self.software_update.update_channel.default_channel
self.software_update.update_channel.default_channel = 'expected_channel'
def tearDown(self):
try:
self.software_update.update_channel.default_channel = self.saved_channel
finally:
@@ -93,17 +93,17 @@ class TestUpdateChannel(FirefoxTestCase)
self.software_update.update_channel.default_channel = 'new_channel'
self.assertEqual(self.software_update.update_channel.default_channel, 'new_channel')
class TestMARChannels(FirefoxTestCase):
def setUp(self):
FirefoxTestCase.setUp(self)
- self.software_update = SoftwareUpdate(lambda: self.marionette)
+ self.software_update = SoftwareUpdate(self.marionette)
self.saved_mar_channels = self.software_update.mar_channels.channels
self.software_update.mar_channels.channels = set(['expected', 'channels'])
def tearDown(self):
try:
self.software_update.mar_channels.channels = self.saved_mar_channels
finally:
--- a/testing/firefox-ui/tests/puppeteer/test_windows.py
+++ b/testing/firefox-ui/tests/puppeteer/test_windows.py
@@ -87,44 +87,42 @@ class TestBaseWindow(BaseWindowTestCase)
def tearDown(self):
try:
self.windows.close_all([self.browser])
finally:
BaseWindowTestCase.tearDown(self)
def test_basics(self):
# force BaseWindow instance
- win1 = BaseWindow(lambda: self.marionette, self.browser.handle)
+ win1 = BaseWindow(self.marionette, self.browser.handle)
self.assertEquals(win1.handle, self.marionette.current_chrome_window_handle)
self.assertEquals(win1.window_element,
self.marionette.find_element(By.CSS_SELECTOR, ':root'))
self.assertEquals(win1.window_element.get_attribute('windowtype'),
self.marionette.get_window_type())
self.assertFalse(win1.closed)
# Test invalid parameters for BaseWindow constructor
- self.assertRaises(TypeError,
- BaseWindow, self.marionette, self.browser.handle)
self.assertRaises(errors.UnknownWindowError,
- BaseWindow, lambda: self.marionette, 10)
+ BaseWindow, self.marionette, 10)
# Test invalid shortcuts
self.assertRaises(KeyError,
win1.send_shortcut, 'l', acel=True)
def test_open_close(self):
# force BaseWindow instance
- win1 = BaseWindow(lambda: self.marionette, self.browser.handle)
+ win1 = BaseWindow(self.marionette, self.browser.handle)
# Open a new window (will be focused), and check states
win2 = win1.open_window()
# force BaseWindow instance
- win2 = BaseWindow(lambda: self.marionette, win2.handle)
+ win2 = BaseWindow(self.marionette, win2.handle)
self.assertEquals(len(self.marionette.chrome_window_handles), 2)
self.assertNotEquals(win1.handle, win2.handle)
self.assertEquals(win2.handle, self.marionette.current_chrome_window_handle)
win2.close()
self.assertTrue(win2.closed)
@@ -139,37 +137,37 @@ class TestBaseWindow(BaseWindowTestCase)
window.marionette.execute_script(""" window.open(); """)
def closer(window):
window.marionette.execute_script(""" window.close(); """)
win2 = win1.open_window(callback=opener)
# force BaseWindow instance
- win2 = BaseWindow(lambda: self.marionette, win2.handle)
+ win2 = BaseWindow(self.marionette, win2.handle)
self.assertEquals(len(self.marionette.chrome_window_handles), 2)
win2.close(callback=closer)
win1.focus()
# Check for an unexpected window class
self.assertRaises(errors.UnexpectedWindowTypeError,
win1.open_window, expected_window_class=BaseWindow)
self.windows.close_all([win1])
def test_switch_to_and_focus(self):
# force BaseWindow instance
- win1 = BaseWindow(lambda: self.marionette, self.browser.handle)
+ win1 = BaseWindow(self.marionette, self.browser.handle)
# Open a new window (will be focused), and check states
win2 = win1.open_window()
# force BaseWindow instance
- win2 = BaseWindow(lambda: self.marionette, win2.handle)
+ win2 = BaseWindow(self.marionette, win2.handle)
self.assertEquals(win2.handle, self.marionette.current_chrome_window_handle)
self.assertEquals(win2.handle, self.windows.focused_chrome_window_handle)
self.assertFalse(win1.focused)
self.assertTrue(win2.focused)
# Switch back to win1 without moving the focus, but focus separately
win1.switch_to()
--- a/testing/puppeteer/firefox/firefox_puppeteer/__init__.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/__init__.py
@@ -1,112 +1,8 @@
# 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.marionette import HTMLElement
-
-from decorators import use_class_as_property
+from firefox_puppeteer.testcases.base import BaseFirefoxTestCase
__version__ = '52.0.0'
-
-
-class Puppeteer(object):
- """The puppeteer class is used to expose libraries to test cases.
-
- example:
- `class MyTestCase(MarionetteTestCase, Puppeteer)`
-
- Each library can be referenced by its puppeteer name as a member of a
- the TestCase instance. For example, from within a test method, the
- "current_window" member of the "Browser" class can be accessed via
- "self.browser.current_window".
- """
-
- def __init__(self):
- self.marionette = None
-
- def get_marionette(self):
- return self.marionette
-
- @use_class_as_property('api.appinfo.AppInfo')
- def appinfo(self):
- """
- Provides access to members of the appinfo api.
-
- See the :class:`~api.appinfo.AppInfo` reference.
- """
-
- @use_class_as_property('api.keys.Keys')
- def keys(self):
- """
- Provides a definition of control keys to use with keyboard shortcuts.
- For example, keys.CONTROL or keys.ALT.
- See the :class:`~api.keys.Keys` reference.
- """
-
- @use_class_as_property('api.places.Places')
- def places(self):
- """Provides low-level access to several bookmark and history related actions.
-
- See the :class:`~api.places.Places` reference.
- """
-
- @use_class_as_property('api.utils.Utils')
- def utils(self):
- """Provides an api for interacting with utility actions.
-
- See the :class:`~api.utils.Utils` reference.
- """
-
- @property
- def platform(self):
- """Returns the lowercased platform name.
-
- :returns: Platform name
- """
- return self.marionette.session_capabilities['platformName']
-
- @use_class_as_property('api.prefs.Preferences')
- def prefs(self):
- """
- Provides an api for setting and inspecting preferences, as see in
- about:config.
-
- See the :class:`~api.prefs.Preferences` reference.
- """
-
- @use_class_as_property('api.security.Security')
- def security(self):
- """
- Provides an api for accessing security related properties and helpers.
-
- See the :class:`~api.security.Security` reference.
- """
-
- @use_class_as_property('ui.windows.Windows')
- def windows(self):
- """
- Provides shortcuts to the top-level windows.
-
- See the :class:`~ui.window.Windows` reference.
- """
-
-
-class DOMElement(HTMLElement):
- """
- Class that inherits from HTMLElement and provides a way for subclasses to
- expose new api's.
- """
-
- def __new__(cls, element):
- instance = object.__new__(cls)
- instance.__dict__ = element.__dict__.copy()
- setattr(instance, 'inner', element)
-
- return instance
-
- def __init__(self, element):
- pass
-
- def get_marionette(self):
- return self.marionette
--- a/testing/puppeteer/firefox/firefox_puppeteer/api/keys.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/api/keys.py
@@ -4,17 +4,15 @@
import marionette_driver
class Keys(marionette_driver.keys.Keys):
"""Proxy to marionette's keys with an "accel" provided for convenience
testing across platforms."""
- def __init__(self, marionette_getter):
- self.marionette_getter = marionette_getter
-
- caps = self.marionette_getter().session_capabilities
+ def __init__(self, marionette):
+ caps = marionette.session_capabilities
self.isDarwin = caps['platformName'] == 'darwin'
@property
def ACCEL(self):
return self.META if self.isDarwin else self.CONTROL
--- a/testing/puppeteer/firefox/firefox_puppeteer/api/utils.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/api/utils.py
@@ -8,17 +8,17 @@ from firefox_puppeteer.base import BaseL
class Utils(BaseLib):
"""Low-level access to utility actions."""
def __init__(self, *args, **kwargs):
BaseLib.__init__(self, *args, **kwargs)
- self._permissions = Permissions(lambda: self.marionette)
+ self._permissions = Permissions(self.marionette)
@property
def permissions(self):
"""Handling of various permissions for hosts.
:returns: Instance of the Permissions class.
"""
return self._permissions
--- a/testing/puppeteer/firefox/firefox_puppeteer/base.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/base.py
@@ -1,23 +1,10 @@
# 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/.
class BaseLib(object):
"""A base class that handles lazily setting the "client" class attribute."""
- def __init__(self, marionette_getter):
- if not callable(marionette_getter):
- raise TypeError('Invalid callback for "marionette_getter": %s' % marionette_getter)
-
- self._marionette = None
- self._marionette_getter = marionette_getter
-
- @property
- def marionette(self):
- if self._marionette is None:
- self._marionette = self._marionette_getter()
- return self._marionette
-
- def get_marionette(self):
- return self.marionette
+ def __init__(self, marionette):
+ self.marionette = marionette
--- a/testing/puppeteer/firefox/firefox_puppeteer/decorators.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/decorators.py
@@ -23,13 +23,13 @@ class use_class_as_property(object):
@wraps(func)
def _(cls, *args, **kwargs):
tag = '_{}_{}'.format(self.mod_name, self.cls_name)
prop = getattr(cls, tag, None)
if not prop:
module = import_module('.{}'.format(self.mod_name),
'firefox_puppeteer')
- prop = getattr(module, self.cls_name)(cls.get_marionette)
+ prop = getattr(module, self.cls_name)(cls.marionette)
setattr(cls, tag, prop)
func(cls, *args, **kwargs)
return prop
return _
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/__init__.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/testcases/__init__.py
@@ -1,5 +1,6 @@
# 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 firefox_puppeteer.testcases.base import BaseFirefoxTestCase
+from firefox_puppeteer.testcases.base import FirefoxPuppeteerMixin
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
@@ -1,43 +1,32 @@
# 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 unittest
-from firefox_puppeteer import Puppeteer
+from marionette import MarionetteTestCase
+
+from firefox_puppeteer.decorators import use_class_as_property
from firefox_puppeteer.ui.browser.window import BrowserWindow
-class BaseFirefoxTestCase(unittest.TestCase, Puppeteer):
- """Base TestCase class for Firefox Desktop tests.
-
- This is designed to enhance MarionetteTestCase by inserting the Puppeteer
- mixin class (so Firefox specific API modules are exposed to test scope) and
- providing common set-up and tear-down code for Firefox tests.
-
- Child classes are expected to also subclass MarionetteTestCase such that
- MarionetteTestCase is inserted into the MRO after FirefoxTestCase but before
- unittest.TestCase.
+class FirefoxPuppeteerMixin(unittest.TestCase):
+ """The puppeteer mixin class is used to expose additional ui and api libraries
+ to test cases.
example:
- `class AwesomeTestCase(FirefoxTestCase, MarionetteTestCase)`
-
- The key role of MarionetteTestCase is to set self.marionette appropriately
- in `__init__`. Any TestCase class that satisfies this requirement is
- compatible with this class.
+ `class MyTestCase(BaseFirefoxTestCase, FirefoxPuppeteerMixin)`
- If you're extending the inheritance tree further to make specialized
- TestCases, favour the use of super() as opposed to explicit calls to a
- parent class.
-
+ Each library can be referenced by its puppeteer name as a member of a
+ the TestCase instance. For example, from within a test method, the
+ "current_window" member of the "Browser" class can be accessed via
+ "self.browser.current_window".
"""
- def __init__(self, *args, **kwargs):
- super(BaseFirefoxTestCase, self).__init__(*args, **kwargs)
def _check_and_fix_leaked_handles(self):
handle_count = len(self.marionette.window_handles)
url = []
try:
# Verify the existence of leaked tabs and print their URLs.
if self._start_handle_count < handle_count:
@@ -75,17 +64,17 @@ class BaseFirefoxTestCase(unittest.TestC
self.marionette.restart(clean=True)
else:
self.marionette.restart(in_app=True)
# Ensure that we always have a valid browser instance available
self.browser = self.windows.switch_to(lambda win: type(win) is BrowserWindow)
def setUp(self, *args, **kwargs):
- super(BaseFirefoxTestCase, self).setUp(*args, **kwargs)
+ super(FirefoxPuppeteerMixin, self).setUp(*args, **kwargs)
self._start_handle_count = len(self.marionette.window_handles)
self._init_tab_handles = self.marionette.window_handles
self.marionette.set_context('chrome')
self.browser = self.windows.current
self.browser.focus()
with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
@@ -98,9 +87,97 @@ class BaseFirefoxTestCase(unittest.TestC
try:
self.prefs.restore_all_prefs()
# This code should be run after all other tearDown code
# so that in case of a failure, further tests will not run
# in a state that is more inconsistent than necessary.
self._check_and_fix_leaked_handles()
finally:
- super(BaseFirefoxTestCase, self).tearDown(*args, **kwargs)
+ super(FirefoxPuppeteerMixin, self).tearDown(*args, **kwargs)
+
+ @use_class_as_property('api.appinfo.AppInfo')
+ def appinfo(self):
+ """
+ Provides access to members of the appinfo api.
+
+ See the :class:`~api.appinfo.AppInfo` reference.
+ """
+
+ @use_class_as_property('api.keys.Keys')
+ def keys(self):
+ """
+ Provides a definition of control keys to use with keyboard shortcuts.
+ For example, keys.CONTROL or keys.ALT.
+ See the :class:`~api.keys.Keys` reference.
+ """
+
+ @use_class_as_property('api.places.Places')
+ def places(self):
+ """Provides low-level access to several bookmark and history related actions.
+
+ See the :class:`~api.places.Places` reference.
+ """
+
+ @use_class_as_property('api.utils.Utils')
+ def utils(self):
+ """Provides an api for interacting with utility actions.
+
+ See the :class:`~api.utils.Utils` reference.
+ """
+
+ @property
+ def platform(self):
+ """Returns the lowercased platform name.
+
+ :returns: Platform name
+ """
+ return self.marionette.session_capabilities['platformName']
+
+ @use_class_as_property('api.prefs.Preferences')
+ def prefs(self):
+ """
+ Provides an api for setting and inspecting preferences, as see in
+ about:config.
+
+ See the :class:`~api.prefs.Preferences` reference.
+ """
+
+ @use_class_as_property('api.security.Security')
+ def security(self):
+ """
+ Provides an api for accessing security related properties and helpers.
+
+ See the :class:`~api.security.Security` reference.
+ """
+
+ @use_class_as_property('ui.windows.Windows')
+ def windows(self):
+ """
+ Provides shortcuts to the top-level windows.
+
+ See the :class:`~ui.window.Windows` reference.
+ """
+
+
+class BaseFirefoxTestCase(MarionetteTestCase, FirefoxPuppeteerMixin):
+ """Base TestCase class for Firefox Desktop tests.
+
+ This is designed to enhance MarionetteTestCase by inserting the Puppeteer
+ mixin class (so Firefox specific API modules are exposed to test scope) and
+ providing common set-up and tear-down code for Firefox tests.
+
+ Child classes are expected to also subclass MarionetteTestCase such that
+ MarionetteTestCase is inserted into the MRO after FirefoxTestCase but before
+ unittest.TestCase.
+
+ example:
+ `class AwesomeTestCase(FirefoxTestCase, MarionetteTestCase)`
+
+ The key role of MarionetteTestCase is to set self.marionette appropriately
+ in `__init__`. Any TestCase class that satisfies this requirement is
+ compatible with this class.
+
+ If you're extending the inheritance tree further to make specialized
+ TestCases, favour the use of super() as opposed to explicit calls to a
+ parent class.
+
+ """
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py
@@ -22,17 +22,17 @@ class Deck(UIBaseLib):
'checkingForUpdates': CheckingForUpdatesPanel,
'downloadAndInstall': DownloadAndInstallPanel,
'downloadFailed': DownloadFailedPanel,
'downloading': DownloadingPanel,
'noUpdatesFound': NoUpdatesFoundPanel,
}
panel = self.element.find_element(By.ID, panel_id)
- return mapping.get(panel_id, Panel)(lambda: self.marionette, self.window, panel)
+ return mapping.get(panel_id, Panel)(self.marionette, self.window, panel)
# Properties for visual elements of the deck #
@property
def apply(self):
"""The :class:`ApplyPanel` instance for the apply panel.
:returns: :class:`ApplyPanel` instance.
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py
@@ -24,12 +24,12 @@ class AboutWindow(BaseWindow):
def deck(self):
"""The :class:`Deck` instance which represents the deck.
:returns: Reference to the deck.
"""
self.switch_to()
deck = self.window_element.find_element(By.ID, 'updateDeck')
- return Deck(lambda: self.marionette, self, deck)
+ return Deck(self.marionette, self, deck)
Windows.register_window(AboutWindow.window_type, AboutWindow)
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py
@@ -5,34 +5,33 @@
from marionette_driver import (
By, Wait
)
from marionette_driver.errors import NoSuchElementException
import firefox_puppeteer.errors as errors
-from firefox_puppeteer import DOMElement
from firefox_puppeteer.api.security import Security
-from firefox_puppeteer.ui_base_lib import UIBaseLib
+from firefox_puppeteer.ui_base_lib import DOMElement, UIBaseLib
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(lambda: self.marionette, self.window)
+ 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'})
@@ -40,17 +39,17 @@ class TabBar(UIBaseLib):
@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(lambda: self.marionette, self.window, tab) for tab in tabs]
+ 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
@@ -205,17 +204,17 @@ class TabBar(UIBaseLib):
class Tab(UIBaseLib):
"""Wraps a tab DOM element."""
def __init__(self, marionette_getter, window, element):
UIBaseLib.__init__(self, marionette_getter, window, element)
- self._security = Security(lambda: self.marionette)
+ 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.
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py
@@ -44,17 +44,17 @@ class NavBar(UIBaseLib):
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(lambda: self.marionette, self.window, 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.
@@ -83,17 +83,17 @@ class LocationBar(UIBaseLib):
@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(lambda: self.marionette,
+ 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)
@@ -207,17 +207,17 @@ class LocationBar(UIBaseLib):
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(lambda: self.marionette,
+ 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.
@@ -447,17 +447,17 @@ class IdentityPopup(UIBaseLib):
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(lambda: self.marionette, self.window, view)
+ 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.
@@ -466,17 +466,17 @@ class IdentityPopupMultiView(UIBaseLib):
: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)(lambda: self.marionette, self.window, view)
+ 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')
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
@@ -74,17 +74,17 @@ class BrowserWindow(BaseWindow):
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(lambda: self.marionette, self, navbar)
+ self._navbar = NavBar(self.marionette, self, navbar)
return self._navbar
@property
def notification(self):
"""Provides access to the currently displayed notification."""
notifications_map = {
@@ -96,17 +96,17 @@ class BrowserWindow(BaseWindow):
}
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)(
- lambda: self.marionette, self, notification)
+ 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.
@@ -137,17 +137,17 @@ class BrowserWindow(BaseWindow):
"""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(lambda: self.marionette, self, tabbrowser)
+ 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
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/menu.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/menu.py
@@ -1,17 +1,17 @@
# 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
from marionette_driver.errors import NoSuchElementException
-from firefox_puppeteer import DOMElement
from firefox_puppeteer.base import BaseLib
+from firefox_puppeteer.ui_base_lib import DOMElement
class MenuBar(BaseLib):
"""Wraps the menubar DOM element inside a browser window."""
@property
def menus(self):
"""A list of :class:`MenuElement` instances corresponding to
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py
@@ -20,17 +20,17 @@ class Deck(UIBaseLib):
mapping = {'feedPanel': FeedPanel,
'generalPanel': GeneralPanel,
'mediaPanel': MediaPanel,
'permPanel': PermissionsPanel,
'securityPanel': SecurityPanel
}
panel = self.element.find_element(By.ID, panel_id)
- return mapping.get(panel_id, Panel)(lambda: self.marionette, self.window, panel)
+ return mapping.get(panel_id, Panel)(self.marionette, self.window, panel)
# Properties for visual elements of the deck #
@property
def feed(self):
"""The :class:`FeedPanel` instance for the feed panel.
:returns: :class:`FeedPanel` instance.
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py
@@ -28,17 +28,17 @@ class PageInfoWindow(BaseWindow):
@property
def deck(self):
"""The :class:`Deck` instance which represents the deck.
:returns: Reference to the deck.
"""
deck = self.window_element.find_element(By.ID, 'mainDeck')
- return Deck(lambda: self.marionette, self, deck)
+ return Deck(self.marionette, self, deck)
def close(self, trigger='shortcut', force=False):
"""Closes the current page info window by using the specified trigger.
:param trigger: Optional, method to close the current window. This can
be a string with one of `menu` (OS X only) or `shortcut`, or a callback
which gets triggered with the current :class:`PageInfoWindow` as parameter.
Defaults to `shortcut`.
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py
@@ -29,17 +29,17 @@ class UpdateWizardDialog(BaseWindow):
@property
def wizard(self):
"""The :class:`Wizard` instance which represents the wizard.
:returns: Reference to the wizard.
"""
# The deck is also the root element
wizard = self.marionette.find_element(By.ID, 'updates')
- return Wizard(lambda: self.marionette, self, wizard)
+ return Wizard(self.marionette, self, wizard)
def select_next_page(self):
"""Clicks on "Next" button, and waits for the next page to show up."""
current_panel = self.wizard.selected_panel
self.wizard.next_button.click()
Wait(self.marionette).until(
lambda _: self.wizard.selected_panel != current_panel,
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
@@ -37,17 +37,17 @@ class Wizard(UIBaseLib):
'updatesfoundbasic': UpdatesFoundBasicPanel,
# TODO: Remove once we no longer support version Firefox 45.0ESR
'incompatibleCheck': IncompatibleCheckPanel,
'incompatibleList': IncompatibleListPanel,
}
panel = self.element.find_element(By.ID, panel_id)
- return mapping.get(panel_id, Panel)(lambda: self.marionette, self.window, panel)
+ return mapping.get(panel_id, Panel)(self.marionette, self.window, panel)
# Properties for visual buttons of the wizard #
@property
def _buttons(self):
return self.element.find_element(By.ANON_ATTRIBUTE, {'anonid': 'Buttons'})
@property
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/windows.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/windows.py
@@ -113,17 +113,17 @@ class Windows(BaseLib):
)
finally:
# Ensure to switch back to the original window
if handle != current_handle:
self.switch_to(current_handle)
if window_type in self.windows_map:
- window = self.windows_map[window_type](lambda: self.marionette, handle)
+ window = self.windows_map[window_type](self.marionette, handle)
else:
raise errors.UnknownWindowError('Unknown window type "%s" for handle: "%s"' %
(window_type, handle))
if expected_class is not None and type(window) is not expected_class:
raise errors.UnexpectedWindowTypeError('Expected window "%s" but got "%s"' %
(expected_class, type(window)))
@@ -214,21 +214,21 @@ class Windows(BaseLib):
class BaseWindow(BaseLib):
"""Base class for any kind of chrome window."""
# l10n class attributes will be set by each window class individually
dtds = []
properties = []
- def __init__(self, marionette_getter, window_handle):
- BaseLib.__init__(self, marionette_getter)
- self._l10n = L10n(self.get_marionette)
- self._prefs = Preferences(self.get_marionette)
- self._windows = Windows(self.get_marionette)
+ def __init__(self, marionette, window_handle):
+ BaseLib.__init__(self, marionette)
+ self._l10n = L10n(self.marionette)
+ self._prefs = Preferences(self.marionette)
+ self._windows = Windows(self.marionette)
if window_handle not in self.marionette.chrome_window_handles:
raise errors.UnknownWindowError('Window with handle "%s" does not exist' %
window_handle)
self._handle = window_handle
def __eq__(self, other):
return self.handle == other.handle
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui_base_lib.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui_base_lib.py
@@ -3,25 +3,42 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_driver.marionette import HTMLElement
from firefox_puppeteer.base import BaseLib
from firefox_puppeteer.ui.windows import BaseWindow
+class DOMElement(HTMLElement):
+ """
+ Class that inherits from HTMLElement and provides a way for subclasses to
+ expose new api's.
+ """
+
+ def __new__(cls, element):
+ instance = object.__new__(cls)
+ instance.__dict__ = element.__dict__.copy()
+ setattr(instance, 'inner', element)
+
+ return instance
+
+ def __init__(self, element):
+ pass
+
+
class UIBaseLib(BaseLib):
"""A base class for all UI element wrapper classes inside a chrome window."""
- def __init__(self, marionette_getter, window, element):
+ def __init__(self, marionette, window, element):
assert isinstance(window, BaseWindow)
assert isinstance(element, HTMLElement)
- BaseLib.__init__(self, marionette_getter)
+ BaseLib.__init__(self, marionette)
self._window = window
self._element = element
@property
def element(self):
"""Returns the reference to the underlying DOM element.
:returns: Reference to the DOM element