Bug 1238733 - Remove dependency on Marionette harness in firefox-puppeteer; r=whimboo
authorMaja Frydrychowicz <mjzffr@gmail.com>
Tue, 22 Mar 2016 12:21:30 -0400
changeset 329944 7e807a003ea4c3a4680f2f0c7bbab8883a1a4db7
parent 329943 8cf36e4c54fe453e13dceceb9e98fdc61c651c8c
child 329945 cc0e742eafa5d1162b062ec12f99c2de9d5ab855
push id1146
push userCallek@gmail.com
push dateMon, 25 Jul 2016 16:35:44 +0000
treeherdermozilla-release@a55778f9cd5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo
bugs1238733
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1238733 - Remove dependency on Marionette harness in firefox-puppeteer; r=whimboo BaseFirefoxTestCase inherits from unittest.TestCase and takes advantage of super() to serve as a cooperative base class for children of MarionetteTestCase. This includes moving UpdateTestCase back into firefox-ui-harness Also update external-media-tests and Firefox UI and Update tests to use BaseFirefoxTestCase MozReview-Commit-ID: 4gsKztEOFrt
dom/media/test/external/external_media_harness/testcase.py
testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
testing/firefox-ui/harness/firefox_ui_harness/testcases.py
testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py
testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py
testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py
testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py
testing/firefox-ui/tests/functional/private_browsing/test_about_private_browsing.py
testing/firefox-ui/tests/functional/security/test_dv_certificate.py
testing/firefox-ui/tests/functional/security/test_enable_privilege.py
testing/firefox-ui/tests/functional/security/test_ev_certificate.py
testing/firefox-ui/tests/functional/security/test_mixed_content_page.py
testing/firefox-ui/tests/functional/security/test_mixed_script_content_blocking.py
testing/firefox-ui/tests/functional/security/test_no_certificate.py
testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py
testing/firefox-ui/tests/functional/security/test_safe_browsing_warning_pages.py
testing/firefox-ui/tests/functional/security/test_security_notification.py
testing/firefox-ui/tests/functional/security/test_ssl_disabled_error_page.py
testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
testing/firefox-ui/tests/functional/security/test_submit_unencrypted_info_warning.py
testing/firefox-ui/tests/functional/security/test_unknown_issuer.py
testing/firefox-ui/tests/functional/security/test_untrusted_connection_error_page.py
testing/firefox-ui/tests/puppeteer/test_about_window.py
testing/firefox-ui/tests/puppeteer/test_appinfo.py
testing/firefox-ui/tests/puppeteer/test_l10n.py
testing/firefox-ui/tests/puppeteer/test_menubar.py
testing/firefox-ui/tests/puppeteer/test_page_info_window.py
testing/firefox-ui/tests/puppeteer/test_places.py
testing/firefox-ui/tests/puppeteer/test_prefs.py
testing/firefox-ui/tests/puppeteer/test_security.py
testing/firefox-ui/tests/puppeteer/test_software_update.py
testing/firefox-ui/tests/puppeteer/test_tabbar.py
testing/firefox-ui/tests/puppeteer/test_toolbars.py
testing/firefox-ui/tests/puppeteer/test_update_wizard.py
testing/firefox-ui/tests/puppeteer/test_utils.py
testing/firefox-ui/tests/puppeteer/test_windows.py
testing/firefox-ui/tests/update/direct/test_direct_update.py
testing/firefox-ui/tests/update/fallback/test_fallback_update.py
testing/puppeteer/firefox/firefox_puppeteer/__init__.py
testing/puppeteer/firefox/firefox_puppeteer/testcases/__init__.py
testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
testing/puppeteer/firefox/firefox_puppeteer/testcases/update.py
testing/puppeteer/firefox/requirements.txt
--- a/dom/media/test/external/external_media_harness/testcase.py
+++ b/dom/media/test/external/external_media_harness/testcase.py
@@ -1,36 +1,36 @@
 # 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 os
 
-from marionette import BrowserMobProxyTestCaseMixin
+from marionette import BrowserMobProxyTestCaseMixin, MarionetteTestCase
 from marionette_driver import Wait
 from marionette_driver.errors import TimeoutException
 from marionette.marionette_test import SkipTest
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_puppeteer.testcases import BaseFirefoxTestCase
 from external_media_tests.utils import (timestamp_now, verbose_until)
 from external_media_tests.media_utils.video_puppeteer import (playback_done, playback_started,
                                          VideoException, VideoPuppeteer as VP)
 
 
-class MediaTestCase(FirefoxTestCase):
+class MediaTestCase(BaseFirefoxTestCase, MarionetteTestCase):
 
     """
     Necessary methods for MSE playback
 
     :param video_urls: Urls you are going to play as part of the tests.
     """
 
     def __init__(self, *args, **kwargs):
         self.video_urls = kwargs.pop('video_urls', False)
-        FirefoxTestCase.__init__(self, *args, **kwargs)
+        super(MediaTestCase, self).__init__(*args, **kwargs)
 
     def save_screenshot(self):
         """
         Make a screenshot of the window that is currently playing the video
         element.
         """
         screenshot_dir = os.path.join(self.marionette.instance.workspace or '',
                                       'screenshots')
@@ -102,27 +102,27 @@ class NetworkBandwidthTestCase(MediaTest
     """
     Test MSE playback while network bandwidth is limited. Uses browsermobproxy
     (https://bmp.lightbody.net/). Please see
     https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
     for more information on setting up browsermob_proxy.
     """
 
     def __init__(self, *args, **kwargs):
-        MediaTestCase.__init__(self, *args, **kwargs)
+        super(NetworkBandwidthTestCase, self).__init__(*args, **kwargs)
         BrowserMobProxyTestCaseMixin.__init__(self, *args, **kwargs)
         self.proxy = None
 
     def setUp(self):
-        MediaTestCase.setUp(self)
+        super(NetworkBandwidthTestCase, self).setUp()
         BrowserMobProxyTestCaseMixin.setUp(self)
         self.proxy = self.create_browsermob_proxy()
 
     def tearDown(self):
-        MediaTestCase.tearDown(self)
+        super(NetworkBandwidthTestCase, self).tearDown()
         BrowserMobProxyTestCaseMixin.tearDown(self)
         self.proxy = None
 
     def run_videos(self):
         """
         Run each of the videos in the video list. Raises if something goes
         wrong in playback.
         """
--- a/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
@@ -5,17 +5,17 @@
 import os
 import shutil
 import tempfile
 
 import mozfile
 import mozinfo
 from marionette import BaseMarionetteTestRunner
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class FirefoxUITestRunner(BaseMarionetteTestRunner):
     def __init__(self, **kwargs):
         BaseMarionetteTestRunner.__init__(self, **kwargs)
         # select the appropriate GeckoInstance
         self.app = 'fxdesktop'
 
--- a/testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
@@ -2,18 +2,18 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 
 import mozfile
 import mozinstall
 
-from firefox_puppeteer.testcases import UpdateTestCase
 from firefox_ui_harness.runners import FirefoxUITestRunner
+from firefox_ui_harness.testcases import UpdateTestCase
 
 
 DEFAULT_PREFS = {
     'app.update.log': True,
     'startup.homepage_override_url': 'about:blank',
 }
 
 
rename from testing/puppeteer/firefox/firefox_puppeteer/testcases/update.py
rename to testing/firefox-ui/harness/firefox_ui_harness/testcases.py
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/update.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
@@ -1,54 +1,60 @@
 # 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 pprint
 from datetime import datetime
 
+from marionette import MarionetteTestCase
 from marionette_driver import Wait
 
 from firefox_puppeteer.api.prefs import Preferences
 from firefox_puppeteer.api.software_update import SoftwareUpdate
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_puppeteer.testcases import BaseFirefoxTestCase
 from firefox_puppeteer.ui.update_wizard import UpdateWizardDialog
 
 
+class FirefoxTestCase(BaseFirefoxTestCase, MarionetteTestCase):
+    """ Integrate MarionetteTestCase with BaseFirefoxTestCase by reordering MRO """
+    pass
+
+
 class UpdateTestCase(FirefoxTestCase):
 
     TIMEOUT_UPDATE_APPLY = 300
     TIMEOUT_UPDATE_CHECK = 30
     TIMEOUT_UPDATE_DOWNLOAD = 360
 
     # For the old update wizard, the errors are displayed inside the dialog. For the
     # handling of updates in the about window the errors are displayed in new dialogs.
     # When the old wizard is open we have to set the preference, so the errors will be
     # shown as expected, otherwise we would have unhandled modal dialogs when errors are
     # raised. See:
     # http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js?rev=a9240b1eb2fb#4813
     # http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js?rev=a9240b1eb2fb#4756
     PREF_APP_UPDATE_ALTWINDOWTYPE = 'app.update.altwindowtype'
 
     def __init__(self, *args, **kwargs):
-        FirefoxTestCase.__init__(self, *args, **kwargs)
+        super(UpdateTestCase, self).__init__(*args, **kwargs)
 
         self.target_buildid = kwargs.pop('update_target_buildid')
         self.target_version = kwargs.pop('update_target_version')
 
         self.update_channel = kwargs.pop('update_channel')
         self.default_update_channel = None
 
         self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
         self.default_mar_channels = None
 
         self.updates = []
 
     def setUp(self, is_fallback=False):
-        FirefoxTestCase.setUp(self)
+        super(UpdateTestCase, self).setUp()
 
         self.software_update = SoftwareUpdate(lambda: self.marionette)
         self.download_duration = None
 
         # Bug 604364 - Preparation to test multiple update steps
         self.current_update_index = 0
 
         self.staging_directory = self.software_update.staging_directory
@@ -105,17 +111,17 @@ class UpdateTestCase(FirefoxTestCase):
         try:
             self.browser.tabbar.close_all_tabs([self.browser.tabbar.selected_tab])
 
             # Print results for now until we have treeherder integration
             output = pprint.pformat(self.updates)
             self.logger.info('Update test results: \n{}'.format(output))
 
         finally:
-            FirefoxTestCase.tearDown(self)
+            super(UpdateTestCase, self).tearDown()
 
             self.restore_config_files()
 
     @property
     def patch_info(self):
         """ Returns information about the active update in the queue.
 
         :returns: A dictionary with information about the active patch
--- a/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
+++ b/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestBrowserWindowShortcuts(FirefoxTestCase):
 
     def test_addons_manager(self):
         # If an about:xyz page is visible, no new tab will be opened
         with self.marionette.using_context('content'):
             self.marionette.navigate('about:')
--- a/testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py
+++ b/testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestAccessLocationBar(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         # Clear complete history so there's no interference from previous entries.
--- a/testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py
+++ b/testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestEscapeAutocomplete(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         # Clear complete history so there's no interference from previous entries.
--- a/testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py
+++ b/testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestFaviconInAutocomplete(FirefoxTestCase):
 
     PREF_SUGGEST_SEARCHES = 'browser.urlbar.suggest.searches'
     PREF_SUGGEST_BOOKMARK = 'browser.urlbar.suggest.bookmark'
 
     def setUp(self):
--- a/testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py
+++ b/testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py
@@ -1,15 +1,15 @@
 # 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 firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestStarInAutocomplete(FirefoxTestCase):
     """ This replaces
     http://hg.mozilla.org/qa/mozmill-tests/file/default/firefox/tests/functional/testAwesomeBar/testSuggestBookmarks.js
     Check a star appears in autocomplete list for a bookmarked page.
     """
 
--- a/testing/firefox-ui/tests/functional/private_browsing/test_about_private_browsing.py
+++ b/testing/firefox-ui/tests/functional/private_browsing/test_about_private_browsing.py
@@ -1,16 +1,16 @@
 # 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.marionette_test import skip_if_e10s
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 from firefox_puppeteer.ui.browser.window import BrowserWindow
 
 
 class TestAboutPrivateBrowsing(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
--- a/testing/firefox-ui/tests/functional/security/test_dv_certificate.py
+++ b/testing/firefox-ui/tests/functional/security/test_dv_certificate.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestDVCertificate(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.locationbar = self.browser.navbar.locationbar
--- a/testing/firefox-ui/tests/functional/security/test_enable_privilege.py
+++ b/testing/firefox-ui/tests/functional/security/test_enable_privilege.py
@@ -1,15 +1,15 @@
 # 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 firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestEnablePrivilege(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = self.marionette.absolute_url('security/enable_privilege.html')
--- a/testing/firefox-ui/tests/functional/security/test_ev_certificate.py
+++ b/testing/firefox-ui/tests/functional/security/test_ev_certificate.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestEVCertificate(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.locationbar = self.browser.navbar.locationbar
--- a/testing/firefox-ui/tests/functional/security/test_mixed_content_page.py
+++ b/testing/firefox-ui/tests/functional/security/test_mixed_content_page.py
@@ -1,15 +1,15 @@
 # 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 Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestMixedContentPage(FirefoxTestCase):
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.locationbar = self.browser.navbar.locationbar
         self.identity_popup = self.locationbar.identity_popup
--- a/testing/firefox-ui/tests/functional/security/test_mixed_script_content_blocking.py
+++ b/testing/firefox-ui/tests/functional/security/test_mixed_script_content_blocking.py
@@ -1,15 +1,15 @@
 # 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 firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestMixedScriptContentBlocking(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = 'https://mozqa.com/data/firefox/security/mixed_content_blocked/index.html'
--- a/testing/firefox-ui/tests/functional/security/test_no_certificate.py
+++ b/testing/firefox-ui/tests/functional/security/test_no_certificate.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 urlparse import urlparse
 
 from marionette_driver import expected, Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestNoCertificate(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.locationbar = self.browser.navbar.locationbar
--- a/testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py
+++ b/testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.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/.
 
 import time
 
 from marionette_driver import By, expected, Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSafeBrowsingNotificationBar(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.test_data = [
--- a/testing/firefox-ui/tests/functional/security/test_safe_browsing_warning_pages.py
+++ b/testing/firefox-ui/tests/functional/security/test_safe_browsing_warning_pages.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/.
 
 import time
 
 from marionette_driver import By, expected, Wait
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSafeBrowsingWarningPages(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.urls = [
--- a/testing/firefox-ui/tests/functional/security/test_security_notification.py
+++ b/testing/firefox-ui/tests/functional/security/test_security_notification.py
@@ -2,17 +2,17 @@
 # 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 time
 
 from marionette_driver import By, Wait
 from marionette_driver.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSecurityNotification(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.urls = [
--- a/testing/firefox-ui/tests/functional/security/test_ssl_disabled_error_page.py
+++ b/testing/firefox-ui/tests/functional/security/test_ssl_disabled_error_page.py
@@ -2,17 +2,17 @@
 # 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 time
 
 from marionette_driver import By
 from marionette_driver.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSSLDisabledErrorPage(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = 'https://tlsv1-0.mozqa.com'
--- a/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
+++ b/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
@@ -1,16 +1,16 @@
 # 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 Wait
 from marionette.marionette_test import skip_if_e10s
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSSLStatusAfterRestart(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.test_data = (
--- a/testing/firefox-ui/tests/functional/security/test_submit_unencrypted_info_warning.py
+++ b/testing/firefox-ui/tests/functional/security/test_submit_unencrypted_info_warning.py
@@ -2,17 +2,17 @@
 # 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, expected, Wait
 
 from marionette_driver.errors import NoAlertPresentException
 from marionette_driver.marionette import Alert
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSubmitUnencryptedInfoWarning(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = 'https://ssl-dv.mozqa.com/data/firefox/security/unencryptedsearch.html'
--- a/testing/firefox-ui/tests/functional/security/test_unknown_issuer.py
+++ b/testing/firefox-ui/tests/functional/security/test_unknown_issuer.py
@@ -2,17 +2,17 @@
 # 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 time
 
 from marionette_driver import By
 from marionette_driver.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestUnknownIssuer(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = 'https://ssl-unknownissuer.mozqa.com'
--- a/testing/firefox-ui/tests/functional/security/test_untrusted_connection_error_page.py
+++ b/testing/firefox-ui/tests/functional/security/test_untrusted_connection_error_page.py
@@ -2,17 +2,17 @@
 # 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 time
 
 from marionette_driver import By, Wait
 from marionette_driver.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestUntrustedConnectionErrorPage(FirefoxTestCase):
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.url = 'https://ssl-selfsigned.mozqa.com'
 
--- a/testing/firefox-ui/tests/puppeteer/test_about_window.py
+++ b/testing/firefox-ui/tests/puppeteer/test_about_window.py
@@ -1,13 +1,13 @@
 # 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 import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestAboutWindow(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.about_window = self.browser.open_about_window()
--- a/testing/firefox-ui/tests/puppeteer/test_appinfo.py
+++ b/testing/firefox-ui/tests/puppeteer/test_appinfo.py
@@ -1,16 +1,16 @@
 # 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 mozversion
 from marionette_driver.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestAppInfo(FirefoxTestCase):
 
     def test_valid_properties(self):
         binary = self.marionette.bin
         version_info = mozversion.get_version(binary=binary)
 
--- a/testing/firefox-ui/tests/puppeteer/test_l10n.py
+++ b/testing/firefox-ui/tests/puppeteer/test_l10n.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 MarionetteException
 
 from firefox_puppeteer.api.l10n import L10n
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestL10n(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
         self.l10n = L10n(lambda: self.marionette)
 
--- a/testing/firefox-ui/tests/puppeteer/test_menubar.py
+++ b/testing/firefox-ui/tests/puppeteer/test_menubar.py
@@ -1,15 +1,15 @@
 # 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.errors import NoSuchElementException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestMenuBar(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
     def test_click_item_in_menubar(self):
--- a/testing/firefox-ui/tests/puppeteer/test_page_info_window.py
+++ b/testing/firefox-ui/tests/puppeteer/test_page_info_window.py
@@ -1,14 +1,14 @@
 # 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 firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestPageInfoWindow(FirefoxTestCase):
 
     def tearDown(self):
         try:
             self.windows.close_all([self.browser])
         finally:
--- a/testing/firefox-ui/tests/puppeteer/test_places.py
+++ b/testing/firefox-ui/tests/puppeteer/test_places.py
@@ -1,15 +1,15 @@
 # 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 firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestPlaces(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.urls = [self.marionette.absolute_url('layout/mozilla_governance.html'),
--- a/testing/firefox-ui/tests/puppeteer/test_prefs.py
+++ b/testing/firefox-ui/tests/puppeteer/test_prefs.py
@@ -1,15 +1,15 @@
 # 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.errors import MarionetteException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class testPreferences(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.new_pref = 'marionette.unittest.set_pref'
--- a/testing/firefox-ui/tests/puppeteer/test_security.py
+++ b/testing/firefox-ui/tests/puppeteer/test_security.py
@@ -1,13 +1,13 @@
 # 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 import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 from firefox_puppeteer.errors import NoCertificateError
 
 
 class TestSecurity(FirefoxTestCase):
 
     def test_get_address_from_certificate(self):
         url = 'https://ssl-ev.mozqa.com'
--- a/testing/firefox-ui/tests/puppeteer/test_software_update.py
+++ b/testing/firefox-ui/tests/puppeteer/test_software_update.py
@@ -1,15 +1,15 @@
 # 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 os
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 from firefox_puppeteer.api.software_update import SoftwareUpdate
 
 
 class TestSoftwareUpdate(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
--- a/testing/firefox-ui/tests/puppeteer/test_tabbar.py
+++ b/testing/firefox-ui/tests/puppeteer/test_tabbar.py
@@ -1,13 +1,13 @@
 # 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 import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 from firefox_puppeteer.errors import NoCertificateError
 
 
 class TestTabBar(FirefoxTestCase):
 
     def tearDown(self):
         try:
--- a/testing/firefox-ui/tests/puppeteer/test_toolbars.py
+++ b/testing/firefox-ui/tests/puppeteer/test_toolbars.py
@@ -1,16 +1,16 @@
 # 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 expected, By, Wait
 from marionette_driver.errors import NoSuchElementException
 
-from firefox_puppeteer.testcases import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestNavBar(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         self.navbar = self.browser.navbar
--- a/testing/firefox-ui/tests/puppeteer/test_update_wizard.py
+++ b/testing/firefox-ui/tests/puppeteer/test_update_wizard.py
@@ -1,13 +1,13 @@
 # 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 import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 from firefox_puppeteer.ui.update_wizard import UpdateWizardDialog
 
 
 class TestUpdateWizard(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
--- a/testing/firefox-ui/tests/puppeteer/test_utils.py
+++ b/testing/firefox-ui/tests/puppeteer/test_utils.py
@@ -1,13 +1,13 @@
 # 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 import FirefoxTestCase
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestSanitize(FirefoxTestCase):
 
     def setUp(self):
         FirefoxTestCase.setUp(self)
 
         # Clear all previous history and cookies.
--- a/testing/firefox-ui/tests/puppeteer/test_windows.py
+++ b/testing/firefox-ui/tests/puppeteer/test_windows.py
@@ -2,18 +2,18 @@
 # 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 NoSuchWindowException, TimeoutException
 
 import firefox_puppeteer.errors as errors
 
-from firefox_puppeteer.testcases import FirefoxTestCase
 from firefox_puppeteer.ui.windows import BaseWindow
+from firefox_ui_harness.testcases import FirefoxTestCase
 
 
 class TestWindows(FirefoxTestCase):
 
     def tearDown(self):
         try:
             self.windows.close_all([self.browser])
         finally:
--- a/testing/firefox-ui/tests/update/direct/test_direct_update.py
+++ b/testing/firefox-ui/tests/update/direct/test_direct_update.py
@@ -1,13 +1,13 @@
 # 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 import UpdateTestCase
+from firefox_ui_harness.testcases import UpdateTestCase
 
 
 class TestDirectUpdate(UpdateTestCase):
 
     def setUp(self):
         UpdateTestCase.setUp(self, is_fallback=False)
 
     def tearDown(self):
--- a/testing/firefox-ui/tests/update/fallback/test_fallback_update.py
+++ b/testing/firefox-ui/tests/update/fallback/test_fallback_update.py
@@ -1,13 +1,13 @@
 # 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 import UpdateTestCase
+from firefox_ui_harness.testcases import UpdateTestCase
 
 
 class TestFallbackUpdate(UpdateTestCase):
 
     def setUp(self):
         UpdateTestCase.setUp(self, is_fallback=True)
 
     def tearDown(self):
--- a/testing/puppeteer/firefox/firefox_puppeteer/__init__.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/__init__.py
@@ -10,31 +10,31 @@ from decorators import use_class_as_prop
 
 
 __version__ = '3.2.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
-    FirefoxTestCase instance. For example, from within a test method, the
+    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
 
-    def set_marionette(self, marionette):
-        self.marionette = 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.
         """
 
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/__init__.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/testcases/__init__.py
@@ -1,6 +1,5 @@
 # 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 FirefoxTestCase
-from firefox_puppeteer.testcases.update import UpdateTestCase
+from firefox_puppeteer.testcases.base import BaseFirefoxTestCase
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
@@ -1,26 +1,43 @@
 # 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 import MarionetteTestCase
+import unittest
 
 from firefox_puppeteer import Puppeteer
 from firefox_puppeteer.ui.browser.window import BrowserWindow
 
 
-class FirefoxTestCase(MarionetteTestCase, Puppeteer):
-    """Base testcase class for Firefox Desktop tests.
+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.
 
-    It enhances the Marionette testcase by inserting the Puppeteer mixin class,
-    so Firefox specific API modules are exposed to test scope.
+    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.
+
     """
     def __init__(self, *args, **kwargs):
-        MarionetteTestCase.__init__(self, *args, **kwargs)
+        super(BaseFirefoxTestCase, self).__init__(*args, **kwargs)
 
     def _check_and_fix_leaked_handles(self):
         handle_count = len(self.marionette.window_handles)
 
         try:
             self.assertEqual(handle_count, self._start_handle_count,
                              'A test must not leak window handles. This test started with '
                              '%s open top level browsing contexts, but ended with %s.' %
@@ -58,18 +75,17 @@ class FirefoxTestCase(MarionetteTestCase
 
         # Marionette doesn't keep the former context, so restore to chrome
         self.marionette.set_context('chrome')
 
         # 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):
-        MarionetteTestCase.setUp(self, *args, **kwargs)
-        Puppeteer.set_marionette(self, self.marionette)
+        super(BaseFirefoxTestCase, self).setUp(*args, **kwargs)
 
         self._start_handle_count = len(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):
             # Ensure that we have a default page opened
@@ -81,9 +97,9 @@ class FirefoxTestCase(MarionetteTestCase
         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:
-            MarionetteTestCase.tearDown(self, *args, **kwargs)
+            super(BaseFirefoxTestCase, self).tearDown(*args, **kwargs)
--- a/testing/puppeteer/firefox/requirements.txt
+++ b/testing/puppeteer/firefox/requirements.txt
@@ -1,5 +1,2 @@
-# The following line can be removed once testcases are no longer part of the puppeteer module.
-marionette-client >= 2.2.0
-
 marionette-driver >= 1.3.0
 mozinfo >= 0.8