Bug 1238733 - Remove dependency on Marionette harness in firefox-puppeteer; r?whimboo;sydpolk draft
authorMaja Frydrychowicz <mjzffr@gmail.com>
Tue, 22 Mar 2016 12:21:30 -0400
changeset 343398 5d2956b10c5bcc3b0e22c25b1c290cdedd9614aa
parent 342865 4037eb98974db1b1e0b5012c8a7f3a36428eaa11
child 343399 c758d9aa3837e1010b93b4d1d37a047d8995e72a
child 343456 4813e99c239c83af0d74ac7543bd73c23f928632
push id13620
push usermjzffr@gmail.com
push dateTue, 22 Mar 2016 16:55:27 +0000
reviewerswhimboo, sydpolk
bugs1238733
milestone48.0a1
Bug 1238733 - Remove dependency on Marionette harness in firefox-puppeteer; r?whimboo;sydpolk 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,30 +1,30 @@
 # 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):
 
     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):
         screenshot_dir = os.path.join(self.marionette.instance.workspace or '',
                                       'screenshots')
         filename = ''.join([self.id().replace(' ', '-'),
                             '_',
                             str(timestamp_now()),
                             '.png'])
@@ -71,27 +71,27 @@ class MediaTestCase(FirefoxTestCase):
         gets recognized a skip in marionette.marionette_test.CommonTestCase.run
         """
         raise SkipTest(reason)
 
 
 class NetworkBandwidthTestCase(MediaTestCase):
 
     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):
         with self.marionette.using_context('content'):
             for url in self.video_urls:
                 video = VP(self.marionette, url,
--- 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